Struct initialization and new operator

牧云@^-^@ 提交于 2021-02-06 15:01:39

问题


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 new operator prior to assigning the a field? Is y still a value type when I init it with new?

public struct X
{
    public int a;
}

public struct Y
{
    public int a { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        X x;
        x.a = 1;

        Y y;
        y.a = 2; // << compile error "unused local variable" here

        Y y2 = new Y();
        y2.a = 3;
    }
}

回答1:


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.




回答2:


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




回答3:


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.




回答4:


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.



来源:https://stackoverflow.com/questions/20226477/struct-initialization-and-new-operator

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!