From http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx
using System;
struct MutableStruct
{
public int Value { get; set; }
public void SetValue(int newValue)
{
Value = newValue;
}
}
class MutableStructHolder
{
public MutableStruct Field;
public MutableStruct Property { get; set; }
}
class Test
{
static void Main(string[] args)
{
MutableStructHolder holder = new MutableStructHolder();
// Affects the value of holder.Field
holder.Field.SetValue(10);
// Retrieves holder.Property as a copy and changes the copy
holder.Property.SetValue(10);
Console.WriteLine(holder.Field.Value);
Console.WriteLine(holder.Property.Value);
}
}
1) Why is a copy (of Property?) being made?
2) When changing the code to holder.Field.Value and holder.Property.Value = 10, I get the error below. That just blew my mind.
Cannot modify the return value of ‘MutableStructHolder.Property’ because it is not a variable
Why would I ever not be allowed to assign a value inside of a property!?! Both properties are get/set!
And finally WHY would you EVER want behavior mentioned in 1 and 2? (It never came up for me, I always used get only properties).
Please explain well, I can’t imagine ever wanting the 2nd much less then the first. It is just so weird to me.
To answer #1: Consider how it would look without an auto-generated property. You’d have
Property { get { return xxx; } }That’s where the copy is made. What looks like referring to a property is really calling a getter method. Would you expect an in-place edit if you had:Of course not, we all depend on return to make a copy of the struct so that the private variable is protected against outside modification. So that’s why it works the way it does.
Now, if you’re thinking that the property setter should have automatically been called with the resulting value, please let me point out that it’s
extremely difficultimpossible to know at compile-time if a call to one of the struct’s methods makes a change (consider if the struct is defined in a different assembly). And writing the value back isn’t just inefficient-but-harmless, it might break correctness. Consider a multithreading scenario, where threads that were only reading from the property under protection of a ReaderWriterLock suddenly are writing back to it. All sorts of pain and misery would occur. So the C# compiler automatically setting the property to the result of your computation just isn’t an option.EDIT: You were wondering why setting a field on the struct generates an error message, but calling a method to do the same thing doesn’t. Well, the method might have useful side effects, so you still need to be able to call it on a temporary copy of the struct. Consider the following variation: