Reference type still needs pass by ref?
Consider the following code (for simplicity, I did not follow any C# coding rules).
public class Professor
{
public string _Name;
public Professor(){}
public Professor(string name)
{
_Name=name;
}
public void Display()
{
Console.WriteLine("Name={0}",_Name);
}
}
public class Example
{
static int Main(string[] args)
{
Professor david = new Professor("David");
Console.WriteLine("\nBefore calling the method ProfessorDetails().. ");
david.Display();
ProfessorDetails(david);
Console.WriteLine("\nAfter calling the method ProfessorDetails()..");
david. Display();
}
static void ProfessorDetails(Professor p)
{
//change in the name here is reflected
p._Name="Flower";
//Why Caller unable to see this assignment
p=new Professor("Jon");
}
}
As expected the output is :
Before calling the method ProfessorDetails()...
Name =David
After calling the method ProfessorDetails()...
Name =Flower
The call p=new Professor("Jon");
in ProfessorDetails(Professor p)
is not effective, even though it is reference type. Why should i still need to use the ref
keyword to get the desired result?
Solution 1:
Everything is passed by value in C#. However, when you pass a reference type, the reference itself is being passed by value, i.e., a copy of the original reference is passed. So, you can change the state of object that the reference copy points to, but if you assign a new value to the reference you are only changing what the copy points to, not the original reference.
When you use the 'ref' keyword it tells the compiler to pass the original reference, not a copy, so you can modify what the reference points to inside of the function. However, the need for this is usually rare and is most often used when you need to return multiple values from a method.
An example:
class Foo
{
int ID { get; set; }
public Foo( int id )
{
ID = id;
}
}
void Main( )
{
Foo f = new Foo( 1 );
Console.WriteLine( f.ID ); // prints "1"
ChangeId( f );
Console.WriteLine( f.ID ); // prints "5"
ChangeRef( f );
Console.WriteLine( f.ID ); // still prints "5", only changed what the copy was pointing to
}
static void ChangeId( Foo f )
{
f.ID = 5;
}
static void ChangeRef( Foo f )
{
f = new Foo( 10 );
}
Solution 2:
You've got pass by reference and reference type mixed up.
By changing p, you're not changing the thing that p points at, but where p itself is pointing at, so to speak. And because p has not been declared as ref, the reference (to the reference type) is passed by value, and the change to p is not reflected in the code calling ProfessorDetails. Changes to the instance p was pointing at are reflected (as that's a reference type). Would Professor have been a value type, not even those changes would be visible in the calling code.
Solution 3:
There is a difference between passing a reference and a reference to a reference.
When you pass an object (of a reference type) the callee can modify the object data through the underlying pointer, but if the callee modifies the reference, when the function returns, the caller does not read the changed reference off the stack. The callee can not change which object is referenced.
When you pass an object by reference, the callee receives a reference to the reference. The callee has a pointer to the original reference, so can modify the reference (thereby changing what object the reference points to) in addition to modifying the object the reference points to.