Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# - ref modifier for ...reference types

Tags:

c#

I am a bit confused about this piece of code.

    public static void Foo(A p)
    {
        p.SomeProp = "ccc";
        p = null; // !!!
    }

    static void Main(string[] args)
    {
        A p = new A();
        Foo(p);

        Console.WriteLine("SomeProp is: " + p.SomeProp);
        Console.ReadLine();
    }

The output is:

"SomeProp is: ccc"

But I would have expected a NullReferenceException.


However, if I change it like so, using the ref modifier:

    public static void Foo(ref A p)
    {
        p.SomeProp = "ccc";
        p = null;
    }

    static void Main(string[] args)
    {
        A p = new A();
        Foo(ref p);

        Console.WriteLine("SomeProp is: " + p.SomeProp);
        Console.ReadLine();
    }

I get a NullReferenceException - the second one is understandable for me.

But how can it be, that in the first piece of code p is NOT set to null, but the property gets its value set?

My question is: what is the p argument of the Foo method in the first piece of code if it is not a reference to the orginal instance?


Btw. here is the definition of class A

public class A
{
    public string SomeProp;
}
like image 749
Max Avatar asked Nov 28 '22 05:11

Max


2 Answers

In .Net, everything is passed by value unless you explicitly use the ref or out keywords. For reference types, that means passing a copy of the reference.

In your first example, that means your p variable is still a reference to the same object, and so setting a property works like you would expect. But when you set the reference itself to null, all you changed was the copy.

like image 52
Joel Coehoorn Avatar answered Dec 19 '22 10:12

Joel Coehoorn


p.SomeValue = "ccc";

is saying:

  • Get the object that p is a reference to
  • Set the value of the property SomeValue on that object to "ccc"

    p = null;

is saying:

  • Change p to, instead of referring to the object it used to, now refer to null.

It is not saying change the object that p refers to to null, but that the local variable p should now refer to null.

By default, when you pass an argument of type A such as in the method invocation "Foo(p)" you are not passing the object that is referenced by p, or even the reference p, but a reference to the object referenced by p. They reference the same object, but they are not the same reference. i.e. the reference p in "public static void Foo(A p)" is not the same reference as the p in "Foo(p)", but they do reference the same object.

You can alter this behaviour by using a ref parameter instead. This changes it so that they are the same reference, and altering the value of one alters the value of the other.

like image 28
ICR Avatar answered Dec 19 '22 09:12

ICR