0

I originally took it from this address: http://csharpindepth.com/articles/chapter8/propertiesmatter.aspx and for some reason I could not get my head around it. Can somebody explain me why Console.WriteLine(holder.Property.Value); outputs 0.

void Main()
{
    MutableStructHolder holder = new MutableStructHolder();
    holder.Field.SetValue(10);
    holder.Property.SetValue(10);
    Console.WriteLine(holder.Field.Value); // Outputs 10
    Console.WriteLine(holder.Property.Value); // Outputs 0
}

struct MutableStruct
{
    public int Value { get; set; }

    public void SetValue(int newValue)
    {
        Value = newValue;
    }
}

class MutableStructHolder
{
    public MutableStruct Field;
    public MutableStruct Property { get; set; }
}
Tarik
  • 79,711
  • 83
  • 236
  • 349
  • { get; set; } are the problem. If I use public MutableStruct Property ; This output 10 and 10 – Poomrokc The 3years Apr 23 '14 at 05:09
  • 4
    Because properties are implemented with hidden get/set methods, and structs are returned by value from the getter. So any modification you make to the Property are not made on the field that the property is wrapping. – Blorgbeard Apr 23 '14 at 05:10

4 Answers4

4
class MutableStructHolder
{
    public MutableStruct Field;
    public MutableStruct Property { get; set; }
}

Is equivalent to

class MutableStructHolder
{
    public MutableStruct Field;

    private MutableStruct _Property;
    public MutableStruct Property { 
       get { return _Property; }
       set { _Property = value; }
    }
}

Which is equivalent to:

class MutableStructHolder
{
    public MutableStruct Field;

    private MutableStruct _Property;
    public MutableStruct getProperty() { 
       return _Property;
    }
    public void setProperty(MutableStruct value) { 
       _Property = value;
    }
}

So, when you do this:

holder.Property.SetValue(10);

You're actually doing this:

holder.getProperty().SetValue(10);

Which is equivalent to:

MutableStruct temp = holder.getProperty(); 
temp.SetValue(10);

And because structs are value types, temp is actually a copy of the underlying _Property field, and your modification is thrown away when it goes out of scope (immediately).

This is a good reason to avoid mutable structs like the plague.

Community
  • 1
  • 1
Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
1

This is because structs are value types and when you pass it around it creates a copies. With field, you are accessing the real version of the structure, while with property, it returns it's copy. You then change this copy and the copy is then thrown away.

Euphoric
  • 12,645
  • 1
  • 30
  • 44
1

The comment in the linked code explains this...

Retrieves holder.Property as a copy and changes the copy

In other words, the .SetValue(10) on holder.Property applies to a copy of holder.Property, not holder.Property itself.

MrBlue
  • 830
  • 6
  • 13
1

When you are accessing the property of holder you are creating a copy of the original struct and then calling the method SetValue on the copy.

The below code would functionally do the same

//First create a copy of the original
var property = new MutableStruct();
property.Value = holder.Property.Value;
//That's not how the copy is actually created but the result is the same

//set the value on the copy
property.SetValue(10);

//print the value of the original
Console.WriteLine(holder.Property.Value);

this happens for properties because properties are essentially methods. When you call the get method a copy of the original is created and it's the copy that's returned by the method not the original

Rune FS
  • 21,497
  • 7
  • 62
  • 96