在依赖项注入中检查null的更好方法 [英] Better way of checking null in dependency injection

查看:57
本文介绍了在依赖项注入中检查null的更好方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When using dependency injection through a constructor I always need to check for nulls before passing the instance to an internal property. e.g.

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

    _user = user;
    _stateManager = statemanager;
} 

在每个控制器/类上重复此模式似乎是重复的。有更好的方法来解决这个问题吗?顺便说一句,不同的控制器将具有不同的构造函数初始化器。我正在为DI使用简单注入器。

repeating this pattern on every controller / class seems repetitive. Is there a better way to handle this? btw different controllers will have different constructor initialisers. I am using Simple Injector for my DI.

推荐答案

这是重复的代码,但这几乎不会成为问题,因为这样做导致在您的代码库中更改扫描?您是否需要更改许多支票?几乎不。看看此博客文章,其中有更多详细信息

It's repetitive code, but it will hardly ever be a problem, because can this cause sweeping changed through your code base? Will you ever need to change many of those checks? Hardly. Take a look at this blog post that goes in more details into this.

说实话,当涉及到我的注入构造函数,我几乎再也不会添加这些null检查了,因为我知道我的DI容器在自动装配这些类型时不会将null引用注入到我的构造函数中。

To be honest, when it comes to my injection constructors, I almost never add those null checks anymore, because I know my DI container will not inject null references into my constructors when auto-wiring those types. This saves me from writing all these null checks at all.

有些人可能会争辩说,现在我在编写代码时要考虑到我的DI容器,但我反对这样做。我只是在编写解决我的问题所需的最少代码。在我的情况下,添加这些null检查不会对我有帮助。

Some people might argue that I now write my code with my DI container in mind, but I would argue against that. I'm just writing the minimal amount of code required that solves my problems. Adding those null checks doesn't help me in my case.

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

But do note that in case I'm writing code for a reusable library, I absolutely do write those null checks, because I have no idea who is calling that code. For constructors that are not used as injection constructors (messages, entities, value types, DTOs) I actually DO add those checks. But here are some ideas how to make this a little bit nicer:

您可以添加一个不错的帮助方法,如下所示:

You can add a nice helper method like this:

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

    _user = user;
    _stateManager = statemanager;
}

这虽然减少了重复代码,但实际上并没有帮助减少生成的机器代码的实际大小(但这几乎没有问题)。因此,您可以使此方法返回如下所示的值:

This however, doesn't really help with reducing duplicate code, although it does reduce the actual size of machine code that is generated (but this hardly ever an issue). So, you could make this method return a value like this:

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

或者...使用C#6.0:

Or... using C# 6.0:

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

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

You can implement this method as follows:

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 不可为空的引用类型,默认情况下可以将引用类型设置为不可为空:

With C# 8 non-nullable reference types, reference types can be made non-nullable by default:

public UserManager(User user, IStateManager stateManager)
{
    _user = user;
    _stateManager = statemanager;
}

请注意,这仅会导致编译时执行,而不会导致运行时执行。没有异常。

Note that this is only causes a compile-time enforcement, not a runtime enforcement. So no exceptions are thrown.

在C#9中可能会改变。有一个建议使用符号添加运行时检查:

This might change with C# 9. There is a proposal for added the runtime checks using the ! symbol:

public UserManager(User user!, IStateManager stateManager!)
{
    _user = user;
    _stateManager = statemanager;
}

这篇关于在依赖项注入中检查null的更好方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆