Home > Mobile >  Does `return new MyType()` return a reference to or a copy of MyType
Does `return new MyType()` return a reference to or a copy of MyType

Time:02-25

Context

public class Person : IDisposable
{
    public Data _data;

    public Person() { _data = new Data(); }

    public void Dispose() { _data = null; }

    public Data GetData()
    {
        // Return a copy of the reference hoping that _data exists as long as we have a reference to it
        // (principle or garbage collection)
        return _data; // Or are we actually returning a copy of _data ??????
    }

}

Question

Tell me where I'm wrong, and answer the "why".

Data data; // Allocate memory for a reference to a Data
Person person; // Allocate memory for a reference to a Person
using (person = new Person())
{
    data = person.GetData(); // We receive the copy of the "reference to the instance" living in the person
}
Console.WriteLine("perons._data null: "   person._data); // The instance of Data has indeed been freed by the Dispose
Console.WriteLine("data not null: "   data); // WHY is data not null even though the Dispose has been called

I'm wondering that because of that stack overflow answer stating that:

The value being returned is not the list, but a reference to the list object, because List is a reference type

Note

Same result if we replace GetData() by:

public Data GetNewData()
{
    Data data = new Data(); // Create a new instance of Data
    // Return a copy of the reference hoping that data exists as long as we have a reference to it
    return data; 
}

Second question

If indeed the instance of Data is copied (returned by value) when we return if from GetData(), then what does a ref return do?

CodePudding user response:

To answer the first question: "WHY is data not null even though the Dispose has been called"

The Dispose sets the local reference to null, the copy of the reference is still in tact.

The _data will be freed when there isn't any rooted reference, meaning no actually running code uses this reference.

See Understanding Garbage Collection in .NET for more information about garbage collection.


A ref return returns the reference itself. So it isn't a copy. Meaning if you set the local reference to null, the other reference will be null as well

CodePudding user response:

This gets a bit complicated in terminology: Instances of classes are returned by reference, but the reference itself is returned by value.

Therefore, in your snippet:

Data data; // Allocate memory for a reference to a Data
Person person; // Allocate memory for a reference to a Person
using (person = new Person())
{
    data = person.GetData(); // **copy** the **reference** from person._data to data
}
Console.WriteLine("perons._data null: "   person._data); // the member of the class has been nullified. This does **not** affect the copy of the reference
Console.WriteLine("data not null: "   data); // The copy of the reference has not been touched

Even though person._data was nullified, the object it points to was and is not eligible for garbage collection, since you still have a reference to it from the local variable data. If Data was itself disposable and would be disposed, using it would likely throw a ObjectDisposedException but there's no guarantee or enforcement that a disposed object is in fact ready for garbage collection.

Using ref return is a really advanced topic (and rarely used) but in this case, it would solve your problem, because if data is declared as ref Data it would be null after the dispose.

CodePudding user response:

Your question body contains a different question than your question title. Let me answer the question in the body first.

A few pictures might help understand this. Let's step through your code and have a look at the situation in memory:

Data data;
Person person;
Local variables             Objects
---------------             -------

person: null
data: null
using (person = new Person()) {
Local variables             Objects
---------------             -------

                             ------------- 
person: ------------------> | Person      |         
data: null                   -------------      ------ 
                            | _data  -----|--> | Data |
                             -------------      ------ 
    data = person.GetData();
Local variables             Objects
---------------             -------

                             ------------- 
person: ------------------> | Person      |         
data: ----                   -------------      ------ 
          |                 | _data  -----|--> | Data |
          |                  -------------      ------ 
          |                                      ^
           -------------------------------------- 
}  // end of using - calls Dispose, sets person._data to null
Local variables             Objects
---------------             -------

                             ------------- 
person: ------------------> | Person      |         
data: ----                   -------------      ------ 
          |                 | _data: null |    | Data |
          |                  -------------      ------ 
          |                                      ^
           -------------------------------------- 

Hence, person._data is null, but data isn't.


For completeness, let me also answer the question in your title:

Does return new MyType() return a reference to or a copy of MyType.

Neither. new MyType() always creates a new object (those boxes on the right-hand side of my drawings) and returns a reference to that object.

  •  Tags:  
  • c#
  • Related