简体   繁体   中英

What happens on the stack with ref parameters in c#?

Im reading some C# documentation about WCF and IDispatchMessageInspector and the interface defines a 'Message' object that is passed by reference so that it can be manipulated.

What actually happens on the stack when you pass something by ref as opposed to passing normally?

It's not the object that's passed by reference - it's the variable .

Basically it aliases the variable used as the argument from the calling side, and the parameter in the method that you call:

public void Foo()
{
    int x = 10;
    Bar(ref x);
    Console.WriteLine(x); // Prints 20
}

public void Bar(ref int y)
{
    y = 20;
}

Here, x and y are essentially the same variable - they refer to the same storage location. Changes made to x are visible via y and vice versa. (Note that in this case it's a local variable in the caller, but it doesn't have to be - if you'd passed an instance variable by reference, then Bar might call another method which changes the same variable, and then y would be seen to "magically" change...)

For more about parameter passing in C#, refer to my article on the subject .

By reference means you can change the original variable passed to the item. It basically passes the address of the variable on the stack rather than the variable value.

IL Dump:

As you actually asked what actually happens on the stack here is an IL dump of a by ref and by value method:

.method private hidebysig instance void  ByRef(string& s) cil managed
{
  // Code size       9 (0x9)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  ldstr      "New value"
  IL_0007:  stind.ref
  IL_0008:  ret
} // end of method Class1::ByRef

vs.

.method private hidebysig instance void  ByValue(string s) cil managed
{
  // Code size       9 (0x9)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "New value"
  IL_0006:  starg.s    s
  IL_0008:  ret
} // end of method Class1::ByValue

As you can see the main difference is the parameter type ( string& instead of string ) and that it does extra steps to load and store the values indirectly.

The simple C# source is shown below for reference:

void ByRef(ref string s)
{
    s = "New value";
}

void ByValue(string s)
{
    s = "New value";
}

When you pass something by value; a copy of the value type is made and put on stack before the function is called. When you pass something by reference then the address of that is pushed on stack instead of creating a copy and when you modify the object in the function then the original object is being modified instead of the copy.

The way it works is that compiler translates your references to variable to indirect memory access when it sees that the argument was passed by ref.

For example let us assume at memory location 100 you have an integer 123; now when you call a function which accepts in by value (which is default) then copy of 123 will be made and pushed on stack before the function is called which means the copy will now be at (lets say) 160 address. However when you pass something by reference then address 100 will be pushed on stack and will reside on location 160.

Now the instructions generated will read 160 to get the location of object and then modify the data at 100. Indirection will happen same as it is done for pointers when you use * operator.

通过ref表示您可以为传递的对象创建新的实例,通过值不能仅仅改变对象的属性

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM