views:

67

answers:

3

Hi, I have following code that does not work due to "a" being a value typed. But I thought it would not work even without accessors, but it did:

class Program
    {
        a _a  //with accessors it WONT compile
        {
            get; 
            set;
        }
        static void Main(string[] args)
        {
            Program p = new Program();
            p._a.X = 5; //when both accessors are deleted, compiler does not
                        //complain about _a.X not being as variable
        }
    }
    struct a
    {
       public int X;
    }

It does not work as "a" is struct. But when I delete accessors from "_a" instance, it works. I do not understand why. Thanks

+1  A: 

You can't delete both accessors.

This way:

a _a;

it works, but it's not a property any more.


Edit: With a property, the value you get from p._a is a result of a function call. If you even modify it, the modified value will by no means "written back" to the "original" _a. Instead, you will just modify a temporary, returned by the getter-function.

C# could allow this, but it would lead to confusion, since people would expect that after p._a.X = 5; int xx = p._a.X; the value of xx would be 5. But it won't be so. Because p_.a is indeed not a variable :-)


The difference is that with

a _a;

your _a is a field; in case of

a _a { get; set; }

_a is a property. And the case

a _a { }

is not allowed.

Vlad
Yes, but when deleted, I can modify the struct this way:p._a.X=5 and it does not says "X is not variable" any more.
Petr
Indeed. With a property, p._a is a function call, it returns a value which cannot be modified. You can assign it to a variable and modify:`a new_a = p._a; new_a.X = 5;`
Vlad
The story is that you cannot modify the "value" of `_a`, because there is no value at all. As it's a property, it is returned by a function, so any changes you are making to it won't be noticed by the class `Program` anyway.
Vlad
+2  A: 

The main feature of value types is that they are copied rather than being passed by reference.

When you have a value type, and an accessor, you essentially have a value type being returned from a method, which causes a copy (the following two examples are the same):

ValueType Property { get { return x; } } // Will make a copy of x
ValueType Method() { return x; }    // Will make a copy of x

If you now assign to the returned value, you're assigning to a copy of x. So any changes made to the value returned from the property will be immediately lost.

When you remove the { get; } accessor, you've now got a basic field, e.g.:

int field;

or

ValueType field;

Which means no copy is made, which means when assigning to the field, you're no longer assigning to a copy.

Groky
The first line is wrong. The rest of the answer is OK. Main difference between value/reference types is what happens when copying them. Not stack/heap.
Henk Holterman
Ok, but I have read that get; and set; are implemented by default. But if it was true, it would not compile.
Petr
@Henk: I knew someone would pick me up on that ;) Truth is they *are* allocated on the stack though! Changed.
Groky
@petr. No, get and set aren't implemented by default. If you remove the accessors, you have a basic field. Think about it, how else do you declare a field?
Groky
@Groky: they *typically* are but not always. Reference types may also go on the stack if the runtime decides it's better (and doesn't affect the logic). But you have my +1 vote!
Isak Savo
@Groky: not always. Value types can be fields inside reference types. And in the end, it does not matter.
Henk Holterman
@petr: you can omit set _or_ get to create a read-only or a write-only property. You can't omit both.
Henk Holterman
Henk: But I can omit both. a _a; will perfectly work
Petr
@Petr: And if you omit both, you make it no longer a property, but a field.
Groky
@Petr: leaving out the `{ }` is what makes it a field. You cannot have an empty `{ }` here.
Henk Holterman
+1  A: 

The reason p._a.X = 5; won't work is because p._a returns a value of the type a. Values cannot change. But if you put the value in a variable, you may change the value of the variable.

Brian Rasmussen