C# 构造函数链接调用顺序
C# constructor chaining call order
我有一个 class,可以用数据或二进制 reader(它用来反序列化数据)创建。它对数据进行额外的初始化,并且由于我不想复制该代码,所以我想链接构造函数。现在这个链接看起来像这样:
public Item(string id, int count = 1) { /*...*/ }
public Item(BinaryReader reader) : this(reader.ReadString(), reader.ReadInt32()) { /*...*/ }
这些读取调用的顺序是确定性的吗?
澄清:我说的是read.ReadString()
和reader.ReadInt32()
的调用顺序。
C# 规范 Run-time evaluation of argument lists 中记录了使用多个参数调用方法时求值顺序的确切行为,其中指出:
During the run-time processing of a function member invocation (Compile-time checking of dynamic overload resolution), the expressions or variable references of an argument list are evaluated in order, from left to right, as follows:
因此在您的情况下,订单将是:
reader.ReadString()
reader.ReadInt32()
- 最后将调用另一个构造函数
现在,这有几个问题,主要与可读性和异常有关。
事实上你问哪个调用顺序是正确的,下一个程序员可能会有同样的问题。最好将其重构为一个不附带很多问题的不同解决方案。
此外,如果您传入 null
reader
,您将得到 NullReferenceException
而不是 ArgumentNullException
,即使您碰巧验证了此参数不在构造函数中 null
,仅仅是因为所有这些评估都将在构造函数主体执行之前发生。有 hacks 到 "fix" 但是它们比你已有的代码更糟糕。
要重构为 "better" 解决方案(我的意见),您将创建一个像这样的工厂方法:
public static Item Create(BinaryReader reader)
{
if (reader == null) throw new ArgumentNullException(nameof(reader));
// optional: handle exceptions from reader.ReadString and ReadInt32
var s = reader.ReadString();
var i = reader.ReadInt32();
return new Item(s, i);
}
我有一个 class,可以用数据或二进制 reader(它用来反序列化数据)创建。它对数据进行额外的初始化,并且由于我不想复制该代码,所以我想链接构造函数。现在这个链接看起来像这样:
public Item(string id, int count = 1) { /*...*/ }
public Item(BinaryReader reader) : this(reader.ReadString(), reader.ReadInt32()) { /*...*/ }
这些读取调用的顺序是确定性的吗?
澄清:我说的是read.ReadString()
和reader.ReadInt32()
的调用顺序。
C# 规范 Run-time evaluation of argument lists 中记录了使用多个参数调用方法时求值顺序的确切行为,其中指出:
During the run-time processing of a function member invocation (Compile-time checking of dynamic overload resolution), the expressions or variable references of an argument list are evaluated in order, from left to right, as follows:
因此在您的情况下,订单将是:
reader.ReadString()
reader.ReadInt32()
- 最后将调用另一个构造函数
现在,这有几个问题,主要与可读性和异常有关。
事实上你问哪个调用顺序是正确的,下一个程序员可能会有同样的问题。最好将其重构为一个不附带很多问题的不同解决方案。
此外,如果您传入 null
reader
,您将得到 NullReferenceException
而不是 ArgumentNullException
,即使您碰巧验证了此参数不在构造函数中 null
,仅仅是因为所有这些评估都将在构造函数主体执行之前发生。有 hacks 到 "fix" 但是它们比你已有的代码更糟糕。
要重构为 "better" 解决方案(我的意见),您将创建一个像这样的工厂方法:
public static Item Create(BinaryReader reader)
{
if (reader == null) throw new ArgumentNullException(nameof(reader));
// optional: handle exceptions from reader.ReadString and ReadInt32
var s = reader.ReadString();
var i = reader.ReadInt32();
return new Item(s, i);
}