C# 表达式主体构造函数 - 有没有办法与 null 检查结合使用?



是否有推荐或首选的方法将 C#7"表达式主体构造函数"与其他活动(如空检查和异常抛出)相结合?

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

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 检查等活动的机会,因为不再有构造函数体。

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

...
public Person(string name, SomeClass 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)
{
_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;
}
}

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

在 sharplab.io 上看到它

我认为"元组赋值"样式是一个很好的简短方式,可以说"我的类是从这些成员初始化的,没有其他事情发生"。 我可以瞥一眼,立即知道这就是作者的意图。

一旦再发生一件事(在您的示例中进行验证),那么您应该使用一个完整的构造函数。 正如你所说,你可以做到,但它读起来要糟糕得多。

实际上,我们只使用这种样式,因为我们还没有记录类型。 当我们拥有这些时,我认为我们不会在代码中看到这种情况。

相关内容

最新更新