Tarik
Tarik

Reputation: 81711

Setting Property Doesn't Set Its Inner Property

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; }
}

Upvotes: 0

Views: 86

Answers (4)

Rune FS
Rune FS

Reputation: 21742

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

Upvotes: 1

Blorgbeard
Blorgbeard

Reputation: 103437

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.

Upvotes: 4

MrBlue
MrBlue

Reputation: 840

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.

Upvotes: 1

Euphoric
Euphoric

Reputation: 12849

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.

Upvotes: 1

Related Questions