Why do properties behave this way?

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 created?
2) When changing the code to holder.Field.Value

and holder.Property.Value = 10

, I get the error below. It just blew my mind.

Cannot change the return value of 'MutableStructHolder.Property' because it is not a variable

Why was I not allowed to assign a value inside a property!?! Both properties: get

/ set

!

And finally, WHY would you like the behavior mentioned in 1 and 2? (It never crossed my mind, I've always only used properties).

Please explain, okay, I can't imagine I ever wanted the second to be much smaller than the first. This is so strange to me.

+2


source to share


4 answers


Answer # 1: Consider what it would look like without the auto-generated property. You will Property { get { return xxx; } }

have Where the copy is made. What looks like a property reference actually calls the getter method. You would expect in-place editing if you had:

private MutableStruct v;
public MutableStruct f()
{
  return v;
}

f() = new MutableStruct();

      

Of course not, we all depend on returning to make a copy of the structure so that the private variable is protected from external modification. So why does it work the way it does.



Now if you think that the property setter should have been called automatically with the resulting value, please let me point out that it is extremely difficult to find out 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 is not just inefficient, but harmless, it can violate correctness. Consider a multithreading scenario where threads that have only read from a property protected by ReaderWriterLock suddenly return to it. All kinds of pain and suffering will appear. So a C # compiler automatically setting a property for the result of your computation is not an option.

EDIT: You wondered why setting a field in a struct generates an error message, but calling a method to do the same does not. Well, the method can have useful side effects, so you will still need to call it on a temporary copy of the structure. Consider the following variation:

struct Mutable
{
    public static int Sum = 0;

    public int x;
    public Mutable(int x) { this.x = x; }
    public void Total() { Sum += x; }
}

class Container
{
    public Mutable Field;
    public Mutable Property { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Container c = new Container();
        c.Field = new Mutable(1);
        c.Property = new Mutable(2);
        c.Field.Total();
        c.Property.Total();
        Console.Out.WriteLine(Mutable.Sum);
    }
}

      

+2


source


1) A copy is performed Property

since it is struct

, and struct

is a value type (as opposed to class

) and copied by value, not by reference.

2) The "cannot change return value" error you see from the nature of the "copy by value" structure. If you change the structure (setting Value

on MutableStruct

through Property

to MutableStructHolder

), your changes will not reflect on it, because you will be changing a copy of the structure, not the structure contained in the property. Since you will never want this behavior, the C # compiler will not let you do this.



Now, if there MutableStruct

was class

, there would be no problem modifying it through a property (and the C # compiler allows you to do this), since you will be working with an actual instance, not a copy.

+3


source


Question 1: . You should read about structures and classes as these papers explain all the "symptoms" that you describe. Structures are not passed by reference, but in fact by copying object instances - the keyword is a copy. So when a property returns a structure, it is actually a copy and not the "real" object that you are changing.

Regarding question 2: The C # compiler understands that setting a variable directly on a structured object obtained via a property doesn't make sense and thus gives you an error. Whether the object obtained via a property is a setter or not does not change this behavior and you will get an error anyway.

Instead of making notes on classes vs structs, I suggest you read Lasse Karlsen's answer to the question " Difference between structs and classes

+2


source


Structures are passed by value, so all you have are copies. Also:

public int Value { get; set; }

      

is shorthand for

private int _Value;
public int Value { 
   get { return _Value; }  
   set { _Value = value; }
}

      

As you can see, there are a lot of copies going on, so complaints are expected. If you use class

which is a reference type, you won't have this problem.

0


source







All Articles