Reputation: 109
I'm wondering to know how ref and out keywords work behind the scenes? For example in case we use it on method will it put this value type variable into some some class in order to work with it as with reference type?
Upvotes: 1
Views: 203
Reputation: 7213
For the ref
you can look at IL code generated for following code:
public static void Main(string[] args)
{
int x = 5;
A(ref x);
}
private static void A(ref int x)
{
x = 10;
}
you will see following:
.method public hidebysig static void Main(string[] args) cil managed
{
. . .
IL_0001: ldc.i4.5 //Push 5 onto the stack as int32.
IL_0002: stloc.0 //Pop a value from stack into local variable 0.
IL_0003: ldloca.s x //Load address of local variable with index indx, short form.
IL_0005: call void ConsoleApp1.Program::A(int32&) //Calls method A() by passing x's address to it
. . .
}
and the method A():
.method private hidebysig static void A(int32& x) cil managed //x's address as argument
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0 //Load argument 0 onto the stack.
IL_0002: ldc.i4.s 10 //Push 10 onto the stack as int32, short form.
IL_0004: stind.i4 //Store value of type int32 into memory at address
IL_0005: ret
}
so basically it passes x
s address to method A()
, inside which the value of 10
will be written into memory with given address.
and finally for the out
:
public static void Main(string[] args)
{
A(out int x);
}
private static void A(out int x)
{
x = 10;
}
the IL code would be:
.method private hidebysig static void A([out] int32& x) cil managed
{
. . .
IL_0001: ldloca.s x //Load address of local variable with index indx, short form.
IL_0003: call void ConsoleApp1.Program::A(int32&) //Calls method A() by passing x's address to it
. . .
}
and the method A():
.method private hidebysig static void A([out] int32& x) cil managed
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.s 10
IL_0004: stind.i4
IL_0005: ret
} // end of method Program::A
as you can see only difference in A(ref int x)
and A(out int x)
methods is [out]
method parameter attribute which will indicate that the parameter passed by out
(not ref
).
Upvotes: 1
Reputation: 1062640
in order to work with it as with reference type?
Firstly, you need to understand that "by reference" (ref
/out
and now in
) is not the same thing as "reference type".
Ultimately, when you see:
void SomeMethod(ref int x);
here x
is a reference, aka a "managed pointer" to a value; the caller supplies the reference. So, when you have:
int a = 123;
SomeMethod(ref a);
this works by taking the address of the variable a
(usually via the ldloca
or ldflda
IL instruction), and passing that address in as the parameter value.
If the body of SomeMethod
is:
void SomeMethod(ref int x) {
Write(x);
x = 12;
}
then the Write(x)
dereferences the pointer x
- it loads the value of x
, looks at where it points, and gets an actual value from there. Likewise, the x=12
takes the value 12
, looks at the pointer x
and writes 12
to where-ever that pointer points.
To write the equivalent in unsafe
C# with C# pointers (aka "unmanaged pointers") to show the difference:
void SomeMethod(int* x) {
Write(*x);
*x = 12;
}
int a = 123;
SomeMethod(&a);
out
is just a fancy version of ref
with certain "definite assignment" conventions; in
is similarly a fancy version of ref
that allows readonly
types to work reliably and efficiently while avoiding stack copies.
Upvotes: 3