C#表达式身体构造器-是否可以与null检查结合使用?

时间:2019-04-08 14:35:08

标签: c#-7.0

是否存在将C#7“表达体构造器”与其他活动(例如,空检查和异常抛出)结合使用的推荐或首选方法?

编写C#类时,我习惯于能够在构造函数中测试参数是否为null(并在需要时抛出异常),如下所示:-

class Person
{
   private string _name;
   private SomeClass _someClass; 

   public Person(string name, SomeClass someClass)
   {
       _name = name ?? throw new ArgumentNullException(nameof(name));
       _someClass = someClass?? throw new ArgumentNullException(nameof(someClass));
   }
}

我刚刚了解了表达体构造器,其中我的代码的简单版本可能如下所示:-

class Person
{
   private string _name;
   private SomeClass _someClass; 

   public Person(string name, SomeClass someClass)
      => (_name, _someClass) = (name, someClass);

}

上面的内容最初看起来很有吸引力,因为它有可能减少为成员变量分配参数所需的样板代码量。

但是,由于不再有构造函数主体,我似乎已经失去了包括上述空检查之类的活动的机会。

据我所知,解决此问题的唯一方法是内联代码,例如我的null-coalesce检查:-

...
   public Person(string name, SomeClass someClass)
      => (_name, _someClass) = 
        (
         name ?? throw new ArgumentNullException(nameof(name ), 
         someClass ?? throw new ArgumentNullException(nameof(someClass)
        ));

即使我试图通过空格来提高可读性,但我认为上面的内容并不像原始示例那样易于阅读-并没有真正保存任何键入内容。

问:有没有更好的方法可以解决这个问题,还是我打败了这种新型构造函数的目的? (即我应该坚持使用原始方法)

2 个答案:

答案 0 :(得分:0)

我不会批评您的尝试。

事实是两个版本生成的代码几乎相同。

class Person
{
   private string _name;
   private string _someClass; 

   public Person(string name, string someClass)
   {
       _name = name ?? throw new ArgumentNullException(nameof(name));
       _someClass = someClass?? throw new ArgumentNullException(nameof(someClass));
   }
}

成为

class Person
{
    private string _name;

    private string _someClass;

    public Person(string name, string someClass)
    {
        if (name == null)
        {
            throw new ArgumentNullException("name");
        }
        _name = name;
        if (someClass == null)
        {
            throw new ArgumentNullException("someClass");
        }
        _someClass = someClass;
    }
}

see it on sharplab.io

class Person
{
   private string _name;
   private string _someClass; 

   public Person(string name, string someClass)
       => (_name, _someClass) = 
           (
               name ?? throw new ArgumentNullException(nameof(name)), 
               someClass ?? throw new ArgumentNullException(nameof(someClass))
           );
}

成为

class Person
{
    private string _name;

    private string _someClass;

    public Person(string name, string someClass)
    {
        if (name == null)
        {
            throw new ArgumentNullException("name");
        }
        if (someClass == null)
        {
            throw new ArgumentNullException("someClass");
        }
        _name = name;
        _someClass = someClass;
    }
}

see it on sharplab.io

答案 1 :(得分:0)

我认为“元组分配”样式是一种很好的简短表达方式,它表示“我的课程是从这些成员初始化的,其他都没有发生”。我看了一眼,立即知道这就是作者的意图。

一旦发生另一件事(在您的示例中进行验证),则应使用完整的构造函数。正如您所说,您可以做到这一点,但阅读起来却糟得多。

真的,我们只使用这种样式是因为我们还没有记录类型。当我们拥有这些功能时,我认为我们不会在代码中看到如此多的内容。