1

I'm reading about structs and classes in C# and to my understanding structs are value types and classes are reference types. But I'm a little confused about how class objects behave when they are passed as parameters to a method.

Assume I have the following code:

public class Program
{
    public static void Main(string[] args)
    {
        var program = new Program();
        var person = new Person
        {
            Firstname = "Bob",
        };

        Console.WriteLine(person.Firstname);
        program.ChangeName(person);
        Console.WriteLine(person.Firstname);
        program.Kill(person);
        Console.WriteLine(person.Firstname);
        Console.Read();
    }

    public void ChangeName(Person p)
    {
        p.Firstname = "Alice";
    }

    public void Kill(Person p)
    {
        p = null;
    }
}

When I pass my instance of the Person class to Program.ChangeName() and change the value of person.Firstname to Alice, the change is reflected on the original person object as instantiated in my Program.Main() which is what I would expect, the p parameter is a reference to person. However, when I attempt to set p to null, there appears to be no change. Why is this?

Dmitry
  • 13,797
  • 6
  • 32
  • 48
Iain
  • 1,724
  • 6
  • 23
  • 39
  • 2
    The parameter Person p is a reference to an object. When you null it out - you are only nulling the reference not the object. – tim Jun 06 '14 at 19:50
  • 2
    Because `p` is a local variable to the called method. All you're doing is changing the reference of the local variable to null instead of the person object that was passed in. – itsme86 Jun 06 '14 at 19:50
  • 1
    All parameters in C# are passed *by value* unless they are specifically marked `ref` or `out`. In the case of a struct, the entire content of the struct is the value that gets passed. If you modify it, your changes do not affect the original, because you modified a copy. In the case of a class, only a reference to the object gets passed, but the *reference* is passed by value. Reassigning a copy of the reference does not affect the original. You can, however, manipulate the contents of the object, because both the original reference and the copied reference point to that same object. – Mike Strobel Jun 06 '14 at 19:51
  • You are simply setting the reference to null, not changing the data at the existing reference. Think about it as if p is a box you can place a block in. Setting p to null takes the block that is in p and sets it aside, but it doesn't do anything to the block that was previously in p. – AJ Henderson Jun 06 '14 at 19:52
  • http://stackoverflow.com/questions/5057267/what-is-the-difference-between-a-reference-type-and-value-type-in-c – Preston Guillot Jun 06 '14 at 19:53

2 Answers2

3

You are setting your copy of the reference to null, which doesn't affect the original value.

It is analogous to (in C++)

Person * myPtr = new Person();
NullFunc(myPtr);

public NullFunc(Person * ptr)
{
   ptr = null;
}

The reference is effectively passed by value, you can't change it. You can change properties on the object that it points to however:

ptr->Name = "Bob";

Clearly affects the original object.

Kevin DiTraglia
  • 25,746
  • 19
  • 92
  • 138
BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
3

When you "pass by reference" you are really passing a copy of the reference, so setting that reference to point to another object (or null) won't affect the original reference. However if you change properties on the object by dereferencing your copy of the pointer, those changes will be seen by the caller.

If you wanted to truly pass by reference and cause your kill method to work, you could add the ref keyword:

public void Kill(ref Person p)
{
    p = null;
}
Kevin DiTraglia
  • 25,746
  • 19
  • 92
  • 138