views:

137

answers:

5

Hi, I know structs are value types but then I do not understand why this works:
EDIT: I mean, why this.Size.Height does not work then?

struct A
{
    int height;

    public int Height
    { 
        get
        {
            return height;
        }

        set
        {
            height = value;
        }
    }
}

//... class Main
{
    A a = A();
    a.Height = 5;  //works. Why? I thought it should say "cannot modify as it is not variable". I think the properties should return copy of this struct...?
}

Second question - I have read I do not need to use "new" with structs but it does not work without it for me.

+3  A: 

I think you are confusing value types with immutability. I think this SO question will help you.

Aaron Daniels
+1  A: 

It is very normal. And why you think that it must not let you to set value for Height ? It is very normal behavior how properties should work. Concerning calling new, yes it is not mandatory for value types. For value types it just calls default constructor which just initializes fields with default values.

Incognito
A: 

A property will return the value that its "get" method returns. It's the same for structs and classes. If you provider a "set" method, it will do whatever the "set" indicates. The only way that Height could not be modified would be either to use a private "set", or not provide a "set" at all.

Cylon Cat
+1  A: 

"this.Size.Height = 5" does not work because when a value type is used as the type of a property, the above line of code would actually mean "this.get_Size().set_Height(5)", and the result of the get_Size() call is a copy of the original, being a value type.

Thus, were it allowed by C#, setting the property value to 5 would change the copy's value rather than the original property value, which is highly undesirable.

Of course, this does not apply when the value type property of a class is changed via a local variable, so this scenario can be safely be supported.

Alan
+5  A: 

Let me break that down into several questions:

What is a variable?

A variable is a storage location that contains a value.

Why are value types called value types?

The value of a variable of value type is a value, and is copied by value. The value of a variable of reference type is a reference and is copied by reference. That is why value types are called value types and reference types are called reference types.

Why does a.Height = 10 work?

To change the value stored in a variable of reference type, you've got to have a variable to begin with. In this case, you do: you have the variable "a". The compiler compiles that as "pass the managed address of the variable 'a' to the Height setter with the argument 10". Therefore the Height property setter knows how to find the location of the value stored in 'a' and mutate it.

Why does a.Size.Height = 10 not work?

To change the value stored in a variable of reference type, you've got to have a variable to begin with. The expression "a.Size" is not a variable; it is a value. a.Size does not give you the variable that backs the property -- in fact, there might not be one. Instead, it gives you the value of the property. Value types are copied by value; this is a copy of the value of the property. This means that the compiler has two choices: it can copy the value into a temporary variable and then mutate that variable, tricking you into thinking that you've mutated the backing store of a.Size. Or, it can give you an error indicating that you're doing something foolish. It does the latter.

Isn't this confusing and vexing?

Yes. The moral of the story is do not make mutable value types. Only make immutable value types. Never have a setter on a value type in the first place; only do the assignment in the constructor. If the thing has to be mutable, make it a reference type.

Do I have to use "new" to make a new instance of a value type?

No. You can also use "default":

Foo f = default(Foo);

If Foo is a value type then this fills in the contents of storage location f with the Foo which has all its fields set to their default values.

Or, if the value type is mutable, you can simply set the values of all the fields. However, you have to set all of them if you do not use a constructor or the default initializer. You have to set all of them including private fields.

But if a struct has all public fields doesn't that violate best practices guidelines in two ways? First, because it has public fields, and second, because it is a mutable value type?

Yes. Don't do that.

Eric Lippert