2015-11-19 18 views
13

Có sự khác biệt nào giữa việc sử dụng [In, Out] và chỉ sử dụng ref khi truyền tham số từ C# đến C++?Sự khác nhau giữa [In, Out] và ref khi sử dụng pinvoke trong C# là gì?

Tôi đã tìm thấy một vài bài đăng SO khác nhau và một số nội dung từ MSDN cũng đến gần với câu hỏi của tôi nhưng không hoàn toàn trả lời. Tôi đoán là tôi có thể sử dụng ref một cách an toàn giống như tôi sẽ sử dụng [In, Out], và marshaller sẽ không hành động khác. Mối quan tâm của tôi là nó sẽ hành động khác nhau, và rằng C + + sẽ không được hạnh phúc với C# struct của tôi được thông qua. Tôi đã nhìn thấy cả những điều thực hiện trong cơ sở mã Tôi đang làm việc tại ...

Sau đây là các bài viết tôi đã tìm thấy và đã được đọc qua:

Are P/Invoke [In, Out] attributes optional for marshaling arrays? Làm cho tôi nghĩ rằng tôi nên sử dụng [ Vào, Ra].

Ba bài viết làm cho tôi nghĩ rằng tôi nên sử dụng [In, Out], nhưng mà tôi có thể sử dụng ref thay vào đó và nó sẽ có cùng mã máy. Điều đó làm cho tôi nghĩ rằng tôi sai - do đó yêu cầu ở đây.

+0

Bạn có thể đưa ra ví dụ cụ thể hay không. Bạn có muốn biết sự khác biệt giữa '[In, Out] ref int foo' và' ref int foo' không? Vì nó là viết tắt, câu hỏi của bạn là thiếu chi tiết, và tôi tin rằng bạn cần một (hoặc nhiều hơn) ví dụ cụ thể. –

+0

Một cái gì đó như, là: [DllImport ("MyDll.dll", CallingConvention = CallingConvention.Cdecl)] private static extern bool myFunction ([In, Out] SomeStruct [] aStruct; giống như sử dụng ref thay cho [In – PerryC

+0

Ngoài ra, bạn vừa kết hợp [In, Out] và ref;)? – PerryC

Trả lời

14

Cách sử dụng ref hoặc outkhông tùy ý. Nếu mã gốc yêu cầu pass-by-reference (một con trỏ) thì bạn phải sử dụng các từ khóa đó nếu loại tham số là một loại giá trị. Vì vậy, jitter biết để tạo ra một con trỏ đến giá trị. Và bạn phải bỏ qua chúng nếu kiểu tham số là một kiểu tham chiếu (lớp), các đối tượng đã là con trỏ dưới mui xe.

Thuộc tính [In] và [Out] là cần thiết để giải quyết sự mơ hồ về con trỏ, chúng không chỉ định luồng dữ liệu. [Trong] luôn luôn được ngụ ý bởi marshaller pinvoke vì vậy không cần phải được tuyên bố rõ ràng. Nhưng bạn phải sử dụng [Out] nếu bạn muốn thấy bất kỳ thay đổi nào được thực hiện bởi mã gốc đối với cấu trúc hoặc thành viên lớp học trong mã của bạn. Các marshaller pinvoke tránh sao chép lại tự động để tránh các chi phí.

Sau đó, không cần phải thực hiện thêm [Out]. Xảy ra khi giá trị là blittable, một từ đắt tiền có nghĩa là giá trị được quản lý hoặc bố cục đối tượng giống với bố cục gốc. Sau đó, trình khắc phục sự cố có thể lấy một phím tắt, ghim đối tượng và chuyển con trỏ đến bộ nhớ đối tượng được quản lý. Bạn chắc chắn sẽ thấy những thay đổi sau đó vì mã gốc đang trực tiếp sửa đổi đối tượng được quản lý.

Một cái gì đó bạn nói chung muốn theo đuổi, nó rất hiệu quả. Bạn trợ giúp bằng cách cho thuộc tính [StructLayout (LayoutKind.Sequential)], nó loại bỏ một tối ưu hóa mà CLR sử dụng để sắp xếp lại các trường để lấy đối tượng nhỏ nhất. Và bằng cách chỉ sử dụng các trường có các loại giá trị đơn giản hoặc bộ đệm kích thước cố định, mặc dù bạn không thường có lựa chọn đó. Không được sử dụng bool, thay vào đó hãy sử dụng byte. Không có cách nào dễ dàng để tìm hiểu xem một loại là blittable, khác hơn là nó không hoạt động chính xác hoặc bằng cách sử dụng trình gỡ lỗi và so sánh các giá trị con trỏ.

Chỉ cần rõ ràng và luôn sử dụng [Out] khi bạn cần. Nó không chi phí bất cứ điều gì nếu nó bật ra không cần thiết. Và đó là tự tài liệu.Và bạn có thể cảm thấy tốt rằng nó vẫn sẽ hoạt động nếu kiến ​​trúc của mã nguồn gốc thay đổi.

+0

Tôi khá chắc chắn rằng đối tượng của tôi không phải là blittable (mặc dù tôi không tích cực). Nếu tôi có một cái gì đó hiện đang [In, Out], sẽ thay đổi nó để chỉ sử dụng [Out] được mã sạch hơn và hành xử theo cùng một cách? Hay nó sẽ là mã sạch hơn để rời khỏi thuộc tính [In, Out] để thể hiện ý định hai chiều? Cảm ơn câu trả lời của bạn. – PerryC

+2

Nếu hai chiều là ý định thì mô tả theo cách đó, * làm * sử dụng [In, Out]. –

+0

Nếu giá trị là blittable và không phải là một loại tham chiếu (trong trường hợp này, một struct trong C#), sẽ sử dụng ref thay vì sử dụng công việc [In, Out] cho rằng struct là tuần tự và chỉ chứa các kiểu nguyên thủy (int, float, gấp đôi)? Điều này có giống với việc sử dụng [In, Out] cho trình soạn thảo marshaller vì trong cả hai trường hợp, nó sẽ ghim đối tượng trong bộ nhớ? – PerryC

Các vấn đề liên quan