tags:

views:

247

answers:

8

Dear All,

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

+3  A: 

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"

Bob
No, all reference types are *not* passed by reference. You are mistaking "passing by reference" for "passing a reference". They are separate concepts, and mixing them only increases the confusion.
Guffa
Reference types are not passed by reference - this is a common misconception. The reference to the object is copied and that copy is passed to the method (which is in effect pass-by-value). The `ref` keyword *does* mean pass by reference - meaning that the reference itself is passed rather than a copy of that reference.
Andrew Hare
That is the point I am trying to make. It seems "pass by reference" is too general, I believe that is why this question was asked.
Bob
@Bob: "Pass by reference" isn't too general - it's just widely misunderstood. It has a very clear and specific meaning which isn't terribly hard to explain, once someone makes up their mind to know about it :)
Jon Skeet
A: 

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.

Fredrik Mörk
So if I get it correctly using Ref one can change the instance in the calling method, otherwise on is using the same instance as before the calling method??
Tony
@Tony: the method can always create a new instance and assign it to the parameter. However, the calling code does not see this new instance unless the call is made using the `ref` keyword.
Fredrik Mörk
A: 

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
flq
A: 

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
Esben Skov Pedersen
+6  A: 

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.

Jon Skeet
mere mortals can just bow down to Tony the Pony ;-)
JohnIdol
Ah, thanks for clearing that up. Guess I was a bit shortsighted in my answer.
Secret Agent Man
+2  A: 

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.

Phil Ross
+2  A: 

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).

JohnIdol
I think I mostly agree with you, but the "in flesh and bones" isn't particularly clear IMO - I think it's clearer to talk about the argument (usually a variable) rather than the reference in this case.
Jon Skeet
thanks, I slightly re-worded
JohnIdol
+1  A: 

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.

Guffa