C# 字段初始化的顺序

C# The order of fields initialization

我以这种方式初始化字段来创建对象:

class Example
{
    public int a;
    public int b;
}

var obj = new Example
{
    a = stream.ReadInt(),
    b = stream.ReadInt()
};

字段"a"总是在字段"b"之前初始化吗?否则,当以不同的顺序从流中减去值时,可能会发生不愉快的错误。谢谢!

UPD:在评论中,很多人不明白我的意思。 我会澄清这个问题。这些记录在不同(.NET、Mono 等)编译器上的行为是否始终相同?

第一个:

var obj = new Example
{
    a = stream.ReadInt(),
    b = stream.ReadInt()
};

第二个:

var a = stream.ReadInt();
var b = stream.ReadInt();

var obj = new Example
{
    a = a,
    b = b
};

此构造称为 "Object Initializer",不应与 object/field 初始化 混淆。在完全构建对象之后修改对象是一种很好的语法。

根据 7.6.10.2 - C# 5.0 规范的对象初始值设定项 中的示例:

An instance of Point can be created and initialized as follows:

Point a = new Point { X = 0, Y = 1 };

which has the same effect as

Point __a = new Point();
  __a.X = 0;
  __a.Y = 1; 
Point a = __a;

规范示例隐含地涵盖了赋值排序(这意味着按特定顺序评估 RHS)以及已创建对象分配的总顺序(即,在处理对象初始值设定项之前,不会将对象分配给字段)。

恕我直言,the relevant part of the C# language specification 相当清楚。它可能不那么模糊,但我没有看到一种允许乱序初始化的方法来解释它:

An object initializer consists of a sequence of member initializers

[强调我的]。 "sequence" 这个词必然意味着一个命令。也许这看起来并不规范,但他们的例子确实如此:

An instance of Point can be created and initialized as follows:

Point a = new Point { X = 0, Y = 1 };

which has the same effect as

Point __a = new Point();
__a.X = 0;
__a.Y = 1;
Point a = __a;

如果编译器作者重新排序分配,他们输出的程序将不符合上述示例。

更一般地说,查看该部分中的其余语言会提供更多信息,因为语言设计者煞费苦心地确保该功能直观地工作,包括使用对象初始化程序的嵌套赋值仅分配一个完整的-形成对象给父 属性.

综上所述,真的不重要。如果您有一个 class,其中两个或更多属性的赋值顺序会影响最终结果,那么您手上的 class 非常危险。应该不惜一切代价避免这种设计,因为在任何情况下都太容易破坏,即使对象初始化的编译器规则相当明确。