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