C# objects by Ref - c#

If one passes an object to a method using the 'Ref' keyword then what is the difference with passing it without the ref keyword?
Because both yield the same result, that the object has been altered when passing control back to the calling object.
Such as this:
class Student
{
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
}
class Program
{
static Student student = new Student();
static void Main( string[] args )
{
student.Age = 30;
student.Name = "StudentA";
Console.WriteLine("Original Student: {0}, Age: {1}", student.Name, student.Age);
SetStudent(ref student);
Console.WriteLine("Student by Ref {0}, Age{1}", student.Name, student.Age);
AnotherStudent(student);
Console.WriteLine("Just Another Student {0}, Age {1}", student.Name, student.Age);
Console.ReadLine();
}
public static void SetStudent( ref Student student )
{
student.Age = 16;
student.Name = "StudentY";
}
public static void AnotherStudent( Student studenta )
{
if (studenta.Equals(student))
{
Console.WriteLine("The same object in memory");
}
studenta.Age = 12;
studenta.Name = "StudentX";
}
}
When the student object is passed to AnotherStudent() it gets altered, event thought it is not passed by 'Ref'.
Can someone explain what is happening here?
EDIT
So what is the difference to passing a pointer to an object in C++ in a function?
Tony

Passing by reference allows the method to change the value of the argument passed to the method - so for a reference type, that allows it to change a variable's value to refer to a different object. Here's an example:
using System;
using System.Text;
class Test
{
static void PassByValue(StringBuilder x)
{
x.Append(" - Modified object in method");
x = new StringBuilder("New StringBuilder object");
}
static void PassByReference(ref StringBuilder x)
{
x.Append(" - Modified object in method");
x = new StringBuilder("New StringBuilder object");
}
static void Main()
{
StringBuilder builder = new StringBuilder("Original");
PassByValue(builder);
Console.WriteLine(builder);
builder = new StringBuilder("Original");
PassByReference(ref builder);
Console.WriteLine(builder);
}
}
In both cases, the original StringBuilder has its contents modified, and then the parameter is assigned a new value. In the "pass by value" case, this doesn't change the value of the builder variable in Main. In the "pass by reference" case, the value of builder refers to the new StringBuilder, so the results are:
Original - Modified object in method
New StringBuilder object
In your case, you're not seeing any difference with or without ref because you're not changing the value of the parameter itself - only the data in the object it refers to.
For more information, see my article on parameter passing.

Try reassigning the student object rather than setting properties of it.
public static void SetStudent( ref Student student )
{
student = new Student();
student.Age = 16;
student.Name = "StudentY";
}
public static void AnotherStudent( Student studenta )
{
studenta = new Student();
studenta.Age = 12;
studenta.Name = "StudentX";
}
Don't think of ref as "passing by reference" because all reference types are passed by reference. Think of it as "reference to this object can be reassigned"

Try changing your two Student methods to:
public static void SetStudent( ref Student student )
{
student = new Student();
student.Age = 16;
student.Name = "StudentY";
}
public static void AnotherStudent( Student studenta )
{
studenta = new Student();
studenta.Age = 12;
studenta.Name = "StudentX";
}
The call to SetStudent will now change your static student variable to reference a new instance because it is passed as a ref. The call to AnotherStudent won't change the reference.

I am limiting the discussion to reference types (everything that is a class, meaning I am not talking about structs or built-in value types). For a full and more detailed discussion you can see this link here.
If you pass reference types without the ref keyword you are passing the reference by value, meaning that a copy of your reference will be made. At this point you can modify the object the ref is pointing to, BUT if you swap in another object (assigning to the ref object you passed in some other object you create) when the function returns the original object that lives outside the function that you passed in is still pointing to the same old reference.
If you pass reference types using the ref keyword instead you can swap in the object you passed in with something else because the reference is not merely being copied - the variable itself is being passed in flesh and bones to the function to do whatever, and you can even make it point to some other address in memory (instantiating another object and assigning it to your ref parameter).
As you point out, in both cases you will be able to modify your object. Basically passing by reference in C# corresponds to passing a simple pointer in C++, while passing without the ref keyword corresponds to passing a constant pointer in C++ (you can make changes but can't make it point to smt else).

Passing a variable by reference and passing a reference type is two different things. You can combine them by passing a reference type varaible by reference.
Passing a variable by reference simply means that the method can change the variable. The method gets access to the variable itself, not just a copy of the value. A variable doesn't have to be a reference type to be passed by reference. The few cases where passing by reference is used is actually mostly with value types.
When passing a reference type by reference, that means that the method gets access to the reference variable, not just a copy of the reference to the object. The method not only have access to the object, but it can also replace the reference in the variable with a reference to a different object.
Passing by reference is rarely needed, and certainly not something that you need to do just because you are passing a reference type as a parameter.

When you pass an object to a method using the ref key word, the called method can update the reference itself, not only the object. That means that in the following code snippet:
object a = new object();
SomeMethod(ref a);
...a may be another object instance after the call than it was before the call. If you pass an object without the ref keyword, the called method can update properties and members of the passed object, but cannot replace the object itself with another instance.

The real difference will become apparent when you do this...
public static void SetStudent( ref Student student )
{
student = new Student { Age = 69, Name="Botox" };
}
...
var a = new Student()
var b = a;
SetStudent(ref a);
object.ReferenceEquals(a, b) // Should be false

These examples illustrates the difference
methodA(ref object a)
{
a = new object();
}
methodB(object a)
{
a = new object();
}
object c = new object();
methodA(ref c); //now c points to an entire new object
methodB(c); // does not change the value of c

Related

FileStream Assignment Inside a Static Method [duplicate]

In C#, I have always thought that non-primitive variables were passed by reference and primitive values passed by value.
So when passing to a method any non-primitive object, anything done to the object in the method would effect the object being passed. (C# 101 stuff)
However, I have noticed that when I pass a System.Drawing.Image object, that this does not seem to be the case? If I pass a system.drawing.image object to another method, and load an image onto that object, then let that method go out of scope and go back to the calling method, that image is not loaded on the original object?
Why is this?
Objects aren't passed at all. By default, the argument is evaluated and its value is passed, by value, as the initial value of the parameter of the method you're calling. Now the important point is that the value is a reference for reference types - a way of getting to an object (or null). Changes to that object will be visible from the caller. However, changing the value of the parameter to refer to a different object will not be visible when you're using pass by value, which is the default for all types.
If you want to use pass-by-reference, you must use out or ref, whether the parameter type is a value type or a reference type. In that case, effectively the variable itself is passed by reference, so the parameter uses the same storage location as the argument - and changes to the parameter itself are seen by the caller.
So:
public void Foo(Image image)
{
// This change won't be seen by the caller: it's changing the value
// of the parameter.
image = Image.FromStream(...);
}
public void Foo(ref Image image)
{
// This change *will* be seen by the caller: it's changing the value
// of the parameter, but we're using pass by reference
image = Image.FromStream(...);
}
public void Foo(Image image)
{
// This change *will* be seen by the caller: it's changing the data
// within the object that the parameter value refers to.
image.RotateFlip(...);
}
I have an article which goes into a lot more detail in this. Basically, "pass by reference" doesn't mean what you think it means.
Lots of good answers had been added. I still want to contribute, might be it will clarify slightly more.
When you pass an instance as an argument to the method it passes the copy of the instance. Now, if the instance you pass is a value type(resides in the stack) you pass the copy of that value, so if you modify it, it won't be reflected in the caller. If the instance is a reference type you pass the copy of the reference(again resides in the stack) to the object. So you got two references to the same object. Both of them can modify the object. But if within the method body, you instantiate new object your copy of the reference will no longer refer to the original object, it will refer to the new object you just created. So you will end up having 2 references and 2 objects.
One more code sample to showcase this:
void Main()
{
int k = 0;
TestPlain(k);
Console.WriteLine("TestPlain:" + k);
TestRef(ref k);
Console.WriteLine("TestRef:" + k);
string t = "test";
TestObjPlain(t);
Console.WriteLine("TestObjPlain:" +t);
TestObjRef(ref t);
Console.WriteLine("TestObjRef:" + t);
}
public static void TestPlain(int i)
{
i = 5;
}
public static void TestRef(ref int i)
{
i = 5;
}
public static void TestObjPlain(string s)
{
s = "TestObjPlain";
}
public static void TestObjRef(ref string s)
{
s = "TestObjRef";
}
And the output:
TestPlain:0
TestRef:5
TestObjPlain:test
TestObjRef:TestObjRef
I guess its clearer when you do it like this. I recommend downloading LinqPad to test things like this.
void Main()
{
var Person = new Person(){FirstName = "Egli", LastName = "Becerra"};
//Will update egli
WontUpdate(Person);
Console.WriteLine("WontUpdate");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateImplicitly(Person);
Console.WriteLine("UpdateImplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateExplicitly(ref Person);
Console.WriteLine("UpdateExplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
}
//Class to test
public class Person{
public string FirstName {get; set;}
public string LastName {get; set;}
public string printName(){
return $"First name: {FirstName} Last name:{LastName}";
}
}
public static void WontUpdate(Person p)
{
//New instance does jack...
var newP = new Person(){FirstName = p.FirstName, LastName = p.LastName};
newP.FirstName = "Favio";
newP.LastName = "Becerra";
}
public static void UpdateImplicitly(Person p)
{
//Passing by reference implicitly
p.FirstName = "Favio";
p.LastName = "Becerra";
}
public static void UpdateExplicitly(ref Person p)
{
//Again passing by reference explicitly (reduntant)
p.FirstName = "Favio";
p.LastName = "Becerra";
}
And that should output
WontUpdate
First name: Egli, Last name: Becerra
UpdateImplicitly
First name: Favio, Last name: Becerra
UpdateExplicitly
First name: Favio, Last name: Becerra
When you pass the the System.Drawing.Image type object to a method you are actually passing a copy of reference to that object.
So if inside that method you are loading a new image you are loading using new/copied reference. You are not making change in original.
YourMethod(System.Drawing.Image image)
{
//now this image is a new reference
//if you load a new image
image = new Image()..
//you are not changing the original reference you are just changing the copy of original reference
}
How did you pass object to method?
Are you doing new inside that method for object? If so, you have to use ref in method.
Following link give you better idea.
http://dotnetstep.blogspot.com/2008/09/passing-reference-type-byval-or-byref.html
Employee e = new Employee();
e.Name = "Mayur";
//Passes the reference as value. Parameters passed by value(default).
e.ReferenceParameter(e);
Console.WriteLine(e.Name); // It will print "Shiv"
class Employee {
public string Name { get; set; }
public void ReferenceParameter(Employee emp) {
//Original reference value updated.
emp.Name = "Shiv";
// New reference created so emp object at calling method will not be updated for below changes.
emp = new Employee();
emp.Name = "Max";
}
}
In Pass By Reference You only add "ref" in the function parameters and one
more thing you should be declaring function "static" because of main is static(#public void main(String[] args))!
namespace preparation
{
public class Program
{
public static void swap(ref int lhs,ref int rhs)
{
int temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args)
{
int a = 10;
int b = 80;
Console.WriteLine("a is before sort " + a);
Console.WriteLine("b is before sort " + b);
swap(ref a, ref b);
Console.WriteLine("");
Console.WriteLine("a is after sort " + a);
Console.WriteLine("b is after sort " + b);
}
}
}
In the latest version of C#, which is C# 9 at this time of writing, objects are by default passed by ref. So any changes made to the object in the calling function will persist in the object in the called function.

C# array not passing to method [duplicate]

In C#, I have always thought that non-primitive variables were passed by reference and primitive values passed by value.
So when passing to a method any non-primitive object, anything done to the object in the method would effect the object being passed. (C# 101 stuff)
However, I have noticed that when I pass a System.Drawing.Image object, that this does not seem to be the case? If I pass a system.drawing.image object to another method, and load an image onto that object, then let that method go out of scope and go back to the calling method, that image is not loaded on the original object?
Why is this?
Objects aren't passed at all. By default, the argument is evaluated and its value is passed, by value, as the initial value of the parameter of the method you're calling. Now the important point is that the value is a reference for reference types - a way of getting to an object (or null). Changes to that object will be visible from the caller. However, changing the value of the parameter to refer to a different object will not be visible when you're using pass by value, which is the default for all types.
If you want to use pass-by-reference, you must use out or ref, whether the parameter type is a value type or a reference type. In that case, effectively the variable itself is passed by reference, so the parameter uses the same storage location as the argument - and changes to the parameter itself are seen by the caller.
So:
public void Foo(Image image)
{
// This change won't be seen by the caller: it's changing the value
// of the parameter.
image = Image.FromStream(...);
}
public void Foo(ref Image image)
{
// This change *will* be seen by the caller: it's changing the value
// of the parameter, but we're using pass by reference
image = Image.FromStream(...);
}
public void Foo(Image image)
{
// This change *will* be seen by the caller: it's changing the data
// within the object that the parameter value refers to.
image.RotateFlip(...);
}
I have an article which goes into a lot more detail in this. Basically, "pass by reference" doesn't mean what you think it means.
Lots of good answers had been added. I still want to contribute, might be it will clarify slightly more.
When you pass an instance as an argument to the method it passes the copy of the instance. Now, if the instance you pass is a value type(resides in the stack) you pass the copy of that value, so if you modify it, it won't be reflected in the caller. If the instance is a reference type you pass the copy of the reference(again resides in the stack) to the object. So you got two references to the same object. Both of them can modify the object. But if within the method body, you instantiate new object your copy of the reference will no longer refer to the original object, it will refer to the new object you just created. So you will end up having 2 references and 2 objects.
One more code sample to showcase this:
void Main()
{
int k = 0;
TestPlain(k);
Console.WriteLine("TestPlain:" + k);
TestRef(ref k);
Console.WriteLine("TestRef:" + k);
string t = "test";
TestObjPlain(t);
Console.WriteLine("TestObjPlain:" +t);
TestObjRef(ref t);
Console.WriteLine("TestObjRef:" + t);
}
public static void TestPlain(int i)
{
i = 5;
}
public static void TestRef(ref int i)
{
i = 5;
}
public static void TestObjPlain(string s)
{
s = "TestObjPlain";
}
public static void TestObjRef(ref string s)
{
s = "TestObjRef";
}
And the output:
TestPlain:0
TestRef:5
TestObjPlain:test
TestObjRef:TestObjRef
I guess its clearer when you do it like this. I recommend downloading LinqPad to test things like this.
void Main()
{
var Person = new Person(){FirstName = "Egli", LastName = "Becerra"};
//Will update egli
WontUpdate(Person);
Console.WriteLine("WontUpdate");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateImplicitly(Person);
Console.WriteLine("UpdateImplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateExplicitly(ref Person);
Console.WriteLine("UpdateExplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
}
//Class to test
public class Person{
public string FirstName {get; set;}
public string LastName {get; set;}
public string printName(){
return $"First name: {FirstName} Last name:{LastName}";
}
}
public static void WontUpdate(Person p)
{
//New instance does jack...
var newP = new Person(){FirstName = p.FirstName, LastName = p.LastName};
newP.FirstName = "Favio";
newP.LastName = "Becerra";
}
public static void UpdateImplicitly(Person p)
{
//Passing by reference implicitly
p.FirstName = "Favio";
p.LastName = "Becerra";
}
public static void UpdateExplicitly(ref Person p)
{
//Again passing by reference explicitly (reduntant)
p.FirstName = "Favio";
p.LastName = "Becerra";
}
And that should output
WontUpdate
First name: Egli, Last name: Becerra
UpdateImplicitly
First name: Favio, Last name: Becerra
UpdateExplicitly
First name: Favio, Last name: Becerra
When you pass the the System.Drawing.Image type object to a method you are actually passing a copy of reference to that object.
So if inside that method you are loading a new image you are loading using new/copied reference. You are not making change in original.
YourMethod(System.Drawing.Image image)
{
//now this image is a new reference
//if you load a new image
image = new Image()..
//you are not changing the original reference you are just changing the copy of original reference
}
How did you pass object to method?
Are you doing new inside that method for object? If so, you have to use ref in method.
Following link give you better idea.
http://dotnetstep.blogspot.com/2008/09/passing-reference-type-byval-or-byref.html
Employee e = new Employee();
e.Name = "Mayur";
//Passes the reference as value. Parameters passed by value(default).
e.ReferenceParameter(e);
Console.WriteLine(e.Name); // It will print "Shiv"
class Employee {
public string Name { get; set; }
public void ReferenceParameter(Employee emp) {
//Original reference value updated.
emp.Name = "Shiv";
// New reference created so emp object at calling method will not be updated for below changes.
emp = new Employee();
emp.Name = "Max";
}
}
In Pass By Reference You only add "ref" in the function parameters and one
more thing you should be declaring function "static" because of main is static(#public void main(String[] args))!
namespace preparation
{
public class Program
{
public static void swap(ref int lhs,ref int rhs)
{
int temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args)
{
int a = 10;
int b = 80;
Console.WriteLine("a is before sort " + a);
Console.WriteLine("b is before sort " + b);
swap(ref a, ref b);
Console.WriteLine("");
Console.WriteLine("a is after sort " + a);
Console.WriteLine("b is after sort " + b);
}
}
}
In the latest version of C#, which is C# 9 at this time of writing, objects are by default passed by ref. So any changes made to the object in the calling function will persist in the object in the called function.

Variable Scope For an Extension Method

I have something interesting that I want to understand little deeper.
I have an extension class that extends int:
public static class MyExtension
{
public static void GetProp(this int i, MyObject o)
{
var val = i;
o.sum = i;
}
}
That uses a class as one of its parameter:
public class MyObject
{
public int sum { get; set; }
}
Now, lets see the unit test class:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void test()
{
int a = 1;
int b = 2;
int sum = 0;
Add(a, b, sum);
//Here, sum=3 but after its execution, sum looses its value and
retains the value sum = 0
int test = 4;
MyObject obj = new MyObject();
test.GetProp(obj);
But in the above code when I pass the variable using the extension
method, the obj.sum retains its value obj.sum = 4 . I am not passing any
value by reference. The first portion of code seems to follow the
passing ByVal. But the second portion of extension method, the value
is retained as if its passed as ByRef
string s = sum.ToString();
string p = obj.sum.ToString();
}
private void Add(int x, int y, int sum)
{
sum = x + y;
}
}
Can someone explain the mechanism behind this. Thanks
All parameters are send by value, unless you specify them with the ref or out keyword. Passing a parameter by value means that the value is copied.
However, when you pass an object by value it's not the object that is copied, it's the reference that is copied. That means that you have two references to the same object, one in the obj variable and one in the o parameter, but only one object.
When the extension method accessed the object, it's the same object as outside the method. Any change to the property made using the o parameter will be visible when you later access it using the obj variable.
This is the difference between passing by reference and passing a reference object (class). In GetProp, you aren't modifying the reference obj, you are modifying the MyObject instance that is referred by obj.
If I understand your question, you're confused about why the sum variable isn't changed when it is passed by value, but the obj.sum property does retain its value when obj is passed by reference. The other answers do a good job of explaining this.
In your question, you pass a parameter by value as a receiver, and this confuses your question a bit. Your question appears to be, "why is it that when I pass normally, it's treated as by-value, but when I pass as a receiver to an extension method, it's by-reference?"
Ah. Try assigning a new value to the receiver and see what happens at the call site:
public static void GetProp(this int i, MyObject o)
{
o.sum = i;
i = 5000;
}
You'll find that the variable test at the call site is not affected by this, since the receiver is also passed by value!

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?
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 );
}
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.
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.
The actual value of p is a reference to the same professor instance as david. Any calls you make on that reference are dereferenced as calls to the same instance as would calls made on david be. However, p is a copy of that reference, it's not the same as david value.
Thus, when you do p = new Professor(), you are changing the value of the reference variable to point to a new instance. However, that does not modify the david reference, which still points to the old instance.
If you were to pass p as ref,the value of p would be a reference to the david reference variable. Modifying it would actually modify the david value to point to a new instance.
Regarding on 'passing a reference type' vs 'passing by ref (by using ref key word)', after my research my take away is this:
If you have a reference type object, and keep this object passing from one method to another, the entire time the objects are pointing to a certain location of the memory. If you work on this object for example by changing the property value, this will cause change to the original object. Think as if, in the different methods you were talking about the same person all the time; and in one method you changed the color of the shirt of that person. So that will cause change in the original person object as well.
But, on your path of jumping from one method to another, if you create a new reference for the object (as you are doing by writing 'p=new Professor("Jon")'), you are basically breaking the link between the object in a new method and the original object. Your 'p' now references to another location in the memory. So whatever change you make in this new location of the memory, it will have no effect whatsoever to the original object. However if you want to change the original object address and have the link, you need to use ref key word. BECAREFUL TO USE THE REF KEYWORD, because once in any method, you make the original address in the memory change to a new address (by using ref keyword), all the changes to the original object done in other methods are now gone.
Every reference type is pass by value to a method call. So you can modify the data inside your instance because it is pointing to the same place, but if you want to modify the instance you should use ref
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(ref david);
Console.WriteLine("\nAfter calling the method ProfessorDetails()..");
david. Display();
}
static void ProfessorDetails(ref Professor p)
{
//change in the name here is reflected
p._Name="Flower";
//Why Caller unable to see this assignment
p=new Professor("Jon");
}
}

Why use the 'ref' keyword when passing an object?

If I am passing an object to a method, why should I use the ref keyword? Isn't this the default behaviour anyway?
For example:
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t.Something = "Bar";
}
}
public class TestRef
{
public string Something { get; set; }
}
The output is "Bar" which means that the object was passed as a reference.
Pass a ref if you want to change what the object is:
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);
void DoSomething(ref TestRef t)
{
t = new TestRef();
t.Something = "Not just a changed t, but a completely different TestRef object";
}
After calling DoSomething, t does not refer to the original new TestRef, but refers to a completely different object.
This may be useful too if you want to change the value of an immutable object, e.g. a string. You cannot change the value of a string once it has been created. But by using a ref, you could create a function that changes the string for another one that has a different value.
It is not a good idea to use ref unless it is needed. Using ref gives the method freedom to change the argument for something else, callers of the method will need to be coded to ensure they handle this possibility.
Also, when the parameter type is an object, then object variables always act as references to the object. This means that when the ref keyword is used you've got a reference to a reference. This allows you to do things as described in the example given above. But, when the parameter type is a primitive value (e.g. int), then if this parameter is assigned to within the method, the value of the argument that was passed in will be changed after the method returns:
int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10
void Change(ref int x)
{
x = 5;
}
void WillNotChange(int x)
{
x = 10;
}
You need to distinguish between "passing a reference by value", and "passing a parameter/argument by reference".
I've written a reasonably long article on the subject to avoid having to write carefully each time this comes up on newsgroups
In .NET when you pass any parameter to a method, a copy is created. In value types means that any modification you make to the value is at the method scope, and is lost when you exit the method.
When passing a Reference Type, a copy is also made, but it is a copy of a reference, i.e. now you have TWO references in memory to the same object. So, if you use the reference to modify the object, it gets modified. But if you modify the reference itself - we must remember it is a copy - then any changes are also lost upon exiting the method.
As people have said before, an assignment is a modification of the reference, thus is lost:
public void Method1(object obj) {
obj = new Object();
}
public void Method2(object obj) {
obj = _privateObject;
}
The methods above does not modifies the original object.
A little modification of your example
using System;
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t = new TestRef();
t.Something = "Bar";
}
}
public class TestRef
{
private string s;
public string Something
{
get {return s;}
set { s = value; }
}
}
Since TestRef is a class (which are reference objects), you can change the contents inside t without passing it as a ref. However, if you pass t as a ref, TestRef can change what the original t refers to. i.e. make it point to a different object.
With ref you can write:
static public void DoSomething(ref TestRef t)
{
t = new TestRef();
}
And t will be changed after the method has completed.
Think of variables (e.g. foo) of reference types (e.g. List<T>) as holding object identifiers of the form "Object #24601". Suppose the statement foo = new List<int> {1,5,7,9}; causes foo to hold "Object #24601" (a list with four items). Then calling foo.Length will ask Object #24601 for its length, and it will respond 4, so foo.Length will equal 4.
If foo is passed to a method without using ref, that method might make changes to Object #24601. As a consequence of such changes, foo.Length might no longer equal 4. The method itself, however, will be unable to change foo, which will continue to hold "Object #24601".
Passing foo as a ref parameter will allow the called method to make changes not just to Object #24601, but also to foo itself. The method might create a new Object #8675309 and store a reference to that in foo. If it does so, foo would no longer hold "Object #24601", but instead "Object #8675309".
In practice, reference-type variables don't hold strings of the form "Object #8675309"; they don't even hold anything that can be meaningfully converted into a number. Even though each reference-type variable will hold some bit pattern, there is no fixed relationship between the bit patterns stored in such variables and the objects they identify. There is no way code could extract information from an object or a reference to it, and later determine whether another reference identified the same object, unless the code either held or knew of a reference that identified the original object.
This is like passing a pointer to a pointer in C. In .NET this will allow you to change what the original T refers to, personally though I think if you are doing that in .NET you have probably got a design issue!
By using the ref keyword with reference types you are effectively passing a reference to the reference. In many ways it's the same as using the out keyword but with the minor difference that there's no guarantee that the method will actually assign anything to the ref'ed parameter.
ref mimics (or behaves) as a global area just for two scopes:
Caller
Callee.
If you're passing a value, however, things are different. You can force a value to be passed by reference. This allows you to pass an integer to a method, for example, and have the method modify the integer on your behalf.

Categories