这是重复的代码,但它几乎不会成为问题,因为这会导致整个代码库发生彻底改变吗?您是否需要更改其中的许多支票?几乎不。请查看this blog post,其中包含更多详细信息。
说实话,当谈到我的injection constructors 时,我几乎不再添加那些空检查,因为我知道我的 DI 容器在自动连接这些类型时不会将空引用注入到我的构造函数中。这让我完全不用编写所有这些空检查。
有些人可能会争辩说我现在编写代码时考虑到了我的 DI 容器,但我会反对这一点。我只是在编写解决我的问题所需的最少量代码。在我的情况下,添加这些空检查对我没有帮助。
但请注意,如果我正在为可重用库编写代码,我绝对会编写那些 null 检查,因为我不知道是谁在调用该代码。对于不用作注入构造函数的构造函数(消息、实体、值类型、DTO),我实际上确实添加了这些检查。但这里有一些想法可以让它变得更好一点:
你可以像这样添加一个很好的辅助方法:
public UserManager(User user, IStateManager stateManager)
{
Requires.IsNotNull(user, "user");
Requires.IsNotNull(statemanager, "statemanager");
_user = user;
_stateManager = statemanager;
}
然而,这并不能真正帮助减少重复代码,尽管它确实减少了生成的机器代码的实际大小(但这几乎不是问题)。所以,你可以让这个方法返回一个像这样的值:
public UserManager(User user, IStateManager stateManager)
{
_user = Requires.IsNotNull(user, "user");
_stateManager = Requires.IsNotNull(statemanager, "statemanager");
}
或者...使用 C# 6.0:
public UserManager(User user, IStateManager stateManager)
{
_user = Requires.IsNotNull(user, nameof(user));
_stateManager = Requires.IsNotNull(statemanager, nameof(statemanager));
}
您可以按如下方式实现此方法:
public static class Requires {
public static T IsNotNull<T>(T instance, string paramName) where T : class {
// Use ReferenceEquals in case T overrides equals.
if (object.ReferenceEquals(null, instance)) {
// Call a method that throws instead of throwing directly. This allows
// this IsNotNull method to be inlined.
ThrowArgumentNullException(paramName);
}
return instance;
}
private static void ThrowArgumentNullException(paramName) {
throw new ArgumentNullException(paramName);
}
}
使用 C# 8 non-nullable reference types,默认情况下可以使引用类型不可为空:
public UserManager(User user, IStateManager stateManager)
{
_user = user;
_stateManager = statemanager;
}
请注意,这只会导致编译时强制执行,而不是运行时强制执行。所以不会抛出异常。
这可能会随着 C# 9 改变。有一个建议使用 ! 符号添加运行时检查:
public UserManager(User user!, IStateManager stateManager!)
{
_user = user;
_stateManager = statemanager;
}