Struct initialization and new operator

后端 未结 4 1357
無奈伤痛
無奈伤痛 2021-02-12 12:58

I have two similar structs in C#, each one holds an integer, but the latter has get/set accessors implemented.

Why do I have to initialize the Y struct with

相关标签:
4条回答
  • 2021-02-12 13:07

    This is covered in the C# specification section 5.3 dealing with "Definite Assignment":

    a struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.

    and:

    An initially unassigned variable (Section 5.3.2) is considered definitely assigned at a given location if all possible execution paths leading to that location contain at least one of the following:
    * A simple assignment (Section 7.13.1) in which the variable is the left operand.
    * ...

    As such, this also works:

    void Main()
    {
        X x;
        x.a = 1;
        x.b = 2;
    
        x.Dump();
    }
    
    public struct X
    {
        public int a;
        public int b;
    }
    

    You can test this in LINQPad.

    Note that there is no way for the compiler to prove that the struct-type variable is considered definitely assigned if you call code on it, and that's what you're doing with a property. As such, before you can use a property on the struct-type variable, it has to be definitely assigned.

    0 讨论(0)
  • 2021-02-12 13:11

    In first case you just assigning field. It doesn't involve actual using of structure, just setting value into memory (struct address + field offset on stack).

    In second case you calling method set_a(int value), but fail because variable is uninitialized.

    In third case constructor initializes it for you, so using variable is ok.

    Update: Here comes the specification!

    "12.3 Definite assignment" (page 122 of ecma-334).

    A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned

    0 讨论(0)
  • 2021-02-12 13:19

    The reason one is valid while the other is not is that you cannot call methods on uninitialised objects. Property setters are methods too.

    public struct X
    {
        public int a;
        public void setA(int value)
        { this.a = value; }
    }
    
    public struct Y
    {
        public int a { get; set; }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            X x;
            x.setA(1); // A: error
            x.a = 2; // B: okay
    
            Y y;
            y.a = 3; // C: equivalent to A
        }
    }
    

    The reason that is not allowed is that the property setter could observe the uninitialised state of the object. The caller does not know whether the property setter merely sets a field, or does more than that.

    0 讨论(0)
  • 2021-02-12 13:19

    The new operator for value types runs the specified constructor. Unlike with reference types, this is optional, so if you don't use new, the default constructor is implicitly run (you cannot specify your own default constructor, so it always has the effect of giving the default value to the fields for their types).

    As for why the compiler error, I'm not really sure. Interestingly, in the C# Interactive window,

    public struct Y
    {
        public int a { get; set; }
    }
    Y test;
    test.a = 5;
    

    works just fine.

    0 讨论(0)
提交回复
热议问题