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 非常危险。应该不惜一切代价避免这种设计,因为在任何情况下都太容易破坏,即使对象初始化的编译器规则相当明确。
我以这种方式初始化字段来创建对象:
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 非常危险。应该不惜一切代价避免这种设计,因为在任何情况下都太容易破坏,即使对象初始化的编译器规则相当明确。