Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between [In, Out] and ref when using pinvoke in C#?

Tags:

Is there a difference between using [In, Out] and just using ref when passing parameters from C# to C++?

I've found a couple different SO posts, and some stuff from MSDN as well that comes close to my question but doesn't quite answer it. My guess is that I can safely use ref just like I would use [In, Out], and that the marshaller won't act any differently. My concern is that it will act differently, and that C++ won't be happy with my C# struct being passed. I've seen both things done in the code base I'm working in...

Here are the posts I've found and have been reading through:

Are P/Invoke [In, Out] attributes optional for marshaling arrays? Makes me think I should use [In, Out].

  • MSDN: InAttribute
  • MSDN: OutAttribute
  • MSDN: Directional Attributes

These three posts make me think that I should use [In, Out], but that I can use ref instead and it will have the same machine code. That makes me think I'm wrong -- hence asking here.

like image 466
PerryC Avatar asked Nov 19 '15 22:11

PerryC


People also ask

What is the difference between out and ref?

ref is used to state that the parameter passed may be modified by the method. in is used to state that the parameter passed cannot be modified by the method. out is used to state that the parameter passed must be modified by the method.

What is ref and out keyword in C# with example?

Ref and out keywords in C# are used to pass arguments within a method or function. Both indicate that an argument/parameter is passed by reference. By default parameters are passed to a method by value. By using these keywords (ref and out) we can pass a parameter by reference.

What does REF mean C#?

The ref keyword in C# is used for passing or returning references of values to or from Methods. Basically, it means that any change made to a value that is passed by reference will reflect this change since you are modifying the value at the address and not just the value.

What is ref in C# with example?

The ref keyword indicates that a value is passed by reference. It is used in four different contexts: In a method signature and in a method call, to pass an argument to a method by reference. For more information, see Passing an argument by reference. In a method signature, to return a value to the caller by reference.


1 Answers

The usage of ref or out is not arbitrary. If the native code requires pass-by-reference (a pointer) then you must use those keywords if the parameter type is a value type. So that the jitter knows to generate a pointer to the value. And you must omit them if the parameter type is a reference type (class), objects are already pointers under the hood.

The [In] and [Out] attributes are then necessary to resolve the ambiguity about pointers, they don't specify the data flow. [In] is always implied by the pinvoke marshaller so doesn't have to be stated explicitly. But you must use [Out] if you expect to see any changes made by the native code to a struct or class member back in your code. The pinvoke marshaller avoids copying back automatically to avoid the expense.

A further quirk then is that [Out] is not often necessary. Happens when the value is blittable, an expensive word that means that the managed value or object layout is identical to the native layout. The pinvoke marshaller can then take a shortcut, pinning the object and passing a pointer to managed object storage. You'll inevitably see changes then since the native code is directly modifying the managed object.

Something you in general strongly want to pursue, it is very efficient. You help by giving the type the [StructLayout(LayoutKind.Sequential)] attribute, it suppresses an optimization that the CLR uses to rearrange the fields to get the smallest object. And by using only fields of simple value types or fixed size buffers, albeit that you don't often have that choice. Never use a bool, use byte instead. There is no easy way to find out if a type is blittable, other than it not working correctly or by using the debugger and compare pointer values.

Just be explicit and always use [Out] when you need it. It doesn't cost anything if it turned out not to be necessary. And it is self-documenting. And you can feel good that it still will work if the architecture of the native code changes.

like image 110
Hans Passant Avatar answered Sep 23 '22 03:09

Hans Passant