C#字段初始化的顺序

时间:2017-12-24 08:14:32

标签: c# object-initializers

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

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

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

是否始终在字段“b”之前初始化字段“a”?否则,当以不同的顺序减去流中的值时,可能会发生令人不快的错误。谢谢!

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
};

2 个答案:

答案 0 :(得分:3)

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

  

对象初始值设定项由序列的成员初始值设定项

组成

[强调我的]。单词" sequence"必然意味着一个订单。也许这似乎并不具有规范性,但他们的例子确实如此:

  

可以按如下方式创建和初始化Point的实例:

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

具有相同的效果
Point __a = new Point();
__a.X = 0;
__a.Y = 1;
Point a = __a;

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

更一般地说,在该部分中查看语言的其余部分是非常有用的,因为语言设计者竭尽全力确保该功能直观地工作,包括对象初始化器的嵌套分配仅指定父属性的完全形成的对象。

所有这一切,真的不应该。如果你有一个课程,其中两个或多个属性的作业顺序影响最终结果,那么你手上就有一个非常危险的课程。应该不惜一切代价避免这样的设计,因为在任何情况下都很容易破解,即使对象初始化的编译器规则相当清楚。

答案 1 :(得分:0)

这种结构被称为"对象初始化器"不应与object / field 初始化混淆。在完全构造之后修改对象是一种很好的语法。

根据C#5.0规范的 7.6.10.2 - Object Initializers 中的示例:

  

可以按如下方式创建和初始化Point的实例:

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

具有相同的效果
Point __a = new Point();
  __a.X = 0;
  __a.Y = 1; 
Point a = __a;

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