Passing Parameter by Value and by Reference ("ref"). CLR Internals
What is the difference between passing parameter by reference (using "ref" keyword) and by value (without using "ref" keyword)?
This is really nice and advance question which demonstrates understanding of .Net internals, especially relationship between Stack and Heap.
Reference Type
Let's make some demonstration and examine behavior and difference between passing reference type object by value and by reference.
First let's create some custom class which we will use in demonstration.
public class Book
{
private decimal _price;
public decimal Price
{
get { return _price; }
set { _price = value; }
}
}
Test
Now please look at the code below and say what is an expected output in both cases.
Passing Reference type by value
static void Main(string[] args)
{
Book APress = new Book();
APress.Price = 100;
Book microsoftPress = APress;
ChangePrice(APress);
Console.WriteLine("Price of APress book is {0}",
APress.Price);
Console.WriteLine("Price of MicrosoftPress is {0}",
microsoftPress.Price);
}
static void ChangePrice(Book book)
{
book.Price = 150;
book = new Book();
book.Price = 300;
}
Passing Reference type by reference (using "ref" keyword)
static void Main(string[] args)
{
Book APress2 = new Book();
APress2.Price = 100;
Book MicrosoftPress2 = APress2;
ChangePriceRef(ref APress2);
Console.WriteLine("Price of APress book is {0}",
APress2.Price);
Console.WriteLine("Price of MicrosoftPress is {0}",
MicrosoftPress2.Price);
}
static void ChangePriceRef(ref Book book)
{
book.Price = 150;
book = new Book();
book.Price = 300;
}
Output
Passing reference type by value
Passing reference type by reference
How does it work?
Case 1: Passing Reference type by value
When we are passing reference type by value (without ref keyword) we actually passing copy of the pointer in the stack which refer to the same object.
In the moment when we instantiated new Book we actually created new object in the Heap and changed reference of pointer. As a result we've got two objects in the Heap and appropriate pointers in the stack.
Now pointers are decoupled and any manipulations with book parameter will not reflect on APress.
Case 2: Passing Reference type by reference
In case of passing type by reference, "ref" keyword insurers that we are passing not a copy but original pointer.
So, when the moment of new Book instantiation came, we created new object and changed reference of pointer to the new object in the Heap:
As you can see, any manipulations after impact original APress.
Value Type
Test
Now we do the similar test but in this case will use primitive types.
Passing primitive type by value (without using ref keyword).
static void Main(string[] args)
{
int x = 10;
int y = x;
TestValueType(x);
Console.WriteLine("x={0}", x);
Console.WriteLine("y={0}", y);
}
static void TestValueType(int z)
{
z = 5;
}
Passing primitive type by reference (using ref keyword).
static void Main(string[] args)
{
int i = 10;
int j = i;
TestValueTypeRef(ref i);
Console.WriteLine("i={0}", i);
Console.WriteLine("j={0}", j);
}
static void TestValueTypeRef(ref int k)
{
k = 5;
}
Output
Passing value type without ref keyword.
Passing value type with ref keyword
How does it work ?
When we passing value type parameter we are actually passing copy but not the original type. We are creating new item in the stack and setting value which equals to original one. That is why any operation provided inside of the method does not impact the original type.
In case of using "ref" keyword CLR insures that original type will be passed to the method but not its copy. Which means any operation provided with input parameter will impact on the value of the original type. That is why in second case value of "i" field has been changed.
Technorati Tags:
.Net,
C#,
Reference Type