1

我有一个可以用数据或二进制读取器(它用来反序列化它的数据)创建的类。它对数据进行了额外的初始化,并且由于我不想复制该代码,因此我想链接构造函数。现在这个链接看起来像这样:

public Item(string id, int count = 1) { /*...*/ }

public Item(BinaryReader reader) : this(reader.ReadString(), reader.ReadInt32()) { /*...*/ }

这些读取调用的顺序是否具有确定性?

澄清:read.ReadString()我说的是和reader.ReadInt32()被调用的顺序。

4

1 回答 1

3

调用具有多个参数的方法时,评估顺序的确切行为记录在 C# 规范参数列表的运行时评估中,其中指出:

在函数成员调用的运行时处理期间(动态重载决议的编译时检查),参数列表的表达式或变量引用按从左到右的顺序计算,如下所示:

所以在你的情况下,订单将是:

  • reader.ReadString()
  • reader.ReadInt32()
  • 最后将调用另一个构造函数

现在,这有几个问题,主要与可读性和异常有关。

问哪个调用顺序是正确的这一事实,下一个程序员可能会有同样的问题。最好将其重构为不附带很多问题的不同解决方案。

此外,如果您传入 a ,null reader您将得到 aNullReferenceException而不是 a ArgumentNullException,即使您应该碰巧验证此参数不在null构造函数中,因为所有这些评估都将在构造函数主体执行之前发生。有一些黑客可以“修复”这个问题,但它们比你已经拥有的代码更糟糕。

要重构为“更好”的解决方案(我的观点),您将创建一个像这样的工厂方法:

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);
}
于 2018-02-21T15:14:59.697 回答