在依赖注入中检查null的更好方法

Jam*_*ith 4 c# asp.net dependency-injection

通过构造函数使用依赖项注入时,我总是需要在将实例传递给内部属性之前检查空值.例如

public UserManager(User user, IStateManager stateManager)
{
    if(user == null) throw new arguementexception("user");
    if(statemanager == null) throw new arguementexception("stateManager");

    _user = user;
    _stateManager = statemanager;
} 
Run Code Online (Sandbox Code Playgroud)

在每个控制器/类上重复这种模式似乎是重复的.有没有更好的方法来处理这个?顺便说一句不同的控制器将有不同的构造函数初始化程序.我正在使用Simple Injector进行DI.

Ste*_*ven 12

这是重复的代码,但它几乎不会成为一个问题,因为这会导致代码库中的彻底更改吗?您是否需要更改许多支票?几乎不.看一下这篇博文,其中详细介绍了这一点.

说实话,说到我的注入构造函数,我几乎再也不会添加那些null检查,因为我知道我的DI容器在自动连接这些类型时不会将空引用注入我的构造函数中.这使我免于编写所有这些空检查.

有些人可能会说我现在用我的DI容器编写代码,但我会反对.我只是编写了解决我问题所需的最少量代码.在我的情况下,添加这些空检查对我没有帮助.

但请注意,如果我正在为可重用的库编写代码,我绝对会编写那些空检查,因为我不知道是谁调用该代码.对于不用作注入构造函数(消息,实体,值类型,DTO)的构造函数,我实际上要添加这些检查.但是这里有一些想法如何使这更好一点:

你可以添加一个很好的帮助方法,如下所示:

public UserManager(User user, IStateManager stateManager)
{
    Requires.IsNotNull(user, "user");
    Requires.IsNotNull(statemanager, "statemanager");

    _user = user;
    _stateManager = statemanager;
}
Run Code Online (Sandbox Code Playgroud)

然而,这并没有真正帮助减少重复代码,尽管它确实减少了生成的机器代码的实际大小(但这几乎不是问题).所以,你可以使这个方法返回一个这样的值:

public UserManager(User user, IStateManager stateManager)
{
    _user = Requires.IsNotNull(user, "user");
    _stateManager = Requires.IsNotNull(statemanager, "statemanager");
}
Run Code Online (Sandbox Code Playgroud)

或者......使用C#6.0:

public UserManager(User user, IStateManager stateManager)
{
    _user = Requires.IsNotNull(user, nameof(user));
    _stateManager = Requires.IsNotNull(statemanager, nameof(statemanager));
}
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式实现此方法:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我们只希望C#8添加不可为空的引用类型.这将允许我们将代码减少到以下内容:

public UserManager(User! user, IStateManager! stateManager)
{
    _user = user;
    _stateManager = statemanager;
}
Run Code Online (Sandbox Code Playgroud)

如果C#在定义类型方面有更好的方法(这是C#6的提案,但从未添加到最终版本中),则以下内容可能会更简化类型定义:

public class UserManager(User! user, IStateManager! stateManager)
{
}
Run Code Online (Sandbox Code Playgroud)

  • 非常干净的方式.谢谢. (3认同)