Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning a value type from a property

I'm getting confused with what happens on the stack and heap in respect to value type properties in classes.

My understanding so far:

When you create a class with a structure (value type) like this:

class Foo
{
  private Bar _BarStruct;
  public Bar BarStruct
  {
    get {return _BarStruct; }
    set {_BarStruct = value; }
   }
}

private struct Bar
{
  public int Number;
  Bar()
  {
    Number = 1;
  }
  Bar(int i)
  {
    Number = i;
  }
}

If you create a class instance like so:

Foo fooObj = new Foo();

The stack and heap will look like this:

https://i962.photobucket.com/albums/ae105/acardy/stackheap-1.jpg(https://i962.photobucket.com/albums/ae105/acardy/stackheap-1.jpg)

...where the Bar structure is embeded in the Foo class in the heap. This makes sense to me, but I start to loose it when we consider modifying the Number integer in the BarStruct class, within the Foo Object. For example:

Foo fooObj = new Foo();
fooObj.BarStruct.Number = 1;

As I understand, this should be returning a copy of BarStruct to live on the stack, which means that any changes of a member of BarStruct would not be carried through to the object, which is why the last line above gives an error.

Is this right so far?

If so, my question is, how come an assignment such as this:

fooObj.BarStruct = new Bar(2);

...is valid and changes the heap value? Surely this is just changing the value on the stack?? Also, (by and by) I find it so confusing that you are able to use new on a value type. To me, new is for allocatting on the heap (as per C++) and feels unnatural to be doing this for items on the stack.

So just to re-iterate the question, Am I correct in my assumption of what happens when a property containing a structure is called and why can you assign a new structure to a copy and yet it still changes the reference on the heap?

Really hope this all make sense.

Yell if you need clarification!

Ta,

Andy.

like image 262
Andy Avatar asked Jan 04 '10 13:01

Andy


1 Answers

Looking at this assignment:

fooObj.BarStruct = new Bar(2);

The assignment isn't changing the value on the stack - it's calling the setter for the property.

In other words, whereas your first assignment is equivalent to:

fooObj.get_BarStruct().Number = 1; // Bad

the second is equivalent to:

fooObj.set_BarStruct(new Bar(2));

Does that help?

Note that the problematic assignment becomes a non-issue if you make your value type immutable to start with - which helps in general, in fact. Mutable value types are a really bad idea in C#; you can get into no end of trouble with them.

In terms of your expectations of "new" - try not to think in C++, basically. C# isn't C++, and various things (destructors, generics, behaviour during construction) will confuse you if you try to effectively write C++ in C#. A "new" statement creates a new instance of a type, whether that's a value type or a reference type.

like image 113
Jon Skeet Avatar answered Oct 29 '22 00:10

Jon Skeet