没有构造函数参数的.NET Core DI

4

到目前为止,我一直使用Unity IOC容器来解决依赖关系,这个方法非常有效。对于Unity DI,我通常会按照以下方式解析实例:

Public class TestClass {
    public TestClass()
    {
        var instance = IOC.resolve<InterfaceClassToResolve>();
    }
}

这很好用,但是看到 .net core 现在提供了一个开箱即用的 DI 容器,我更愿意使用它-与 Unity IOC 相比只有一个问题,那就是它作为构造函数参数注入,而不像上面的示例一样解析。
在大多数情况下,我发现它迫使我在多个类中链接我的依赖项,而不是仅在实际需要它们的类中解析我的依赖项。
我一直在寻找解决办法,据我所见,唯一的选择是做这样的事情:
Public class TestClass {
    public TestClass(IServiceProvider serviceProvider)
    {
        var instance = serviceProvider.GetService<InterfaceClassToResolve>();
    }
}

然后我们又回到了原点...

因此,我是不是错过了一些 .net core IOC 的功能,或者说大多数示例都想让我通过构造函数参数使用 .net core IOC 的某些秘密酱汁?


3
在您的两个代码示例中,您使用的是服务定位器模式(Service Locator pattern),而不是依赖注入(Dependency Injection)。依赖注入是指将依赖作为构造函数参数进行注入,而不是像上面的示例那样解析。能否提供更多有关您要解决的问题的信息? - Jonesopolis
2
我认为秘诀在于服务定位器模式现在常被视为反模式,这可能是为什么它不被 .Net Core 支持的原因。 - Matthew Watson
首先,IoC 并不代表特定的库。IoC 简单地意味着控制反转,它就是这样做的。依赖项通过构造函数参数传递而不是使用“new”语句创建(服务定位器本质上与“new”语句几乎相同,只是它管理实例化对象的生命周期)。DI 意味着:依赖注入,可以通过仅通过构造函数传递对象而无需任何框架来完成。服务定位器隐藏了依赖项(检查类的人不知道它正在请求什么,因此在不知道来源的情况下无法有效地对其进行单元测试)。 - Tseng
1
构造函数注入使依赖关系明显,并能清晰展示出代码异味、设计缺陷和单一职责原则的违反情况。 - Tseng
1
这很有道理!因此,在类层次结构中链接依赖关系实际上是一件好事,而不是在我需要依赖项的每个类中都要进行“new”。 - Jeppe Christensen
这个问题有一个关于服务定位器的很好的讨论。 - stuartd
2个回答

1

您可以在不使用构造函数的情况下使用 DI,例如:

ConfigureServices 中:

services.AddSingleton<YourClass>()

然后像这样注入它:

private YourClass YourClass
{
    get
    {
        return this.serviceProvider.GetRequiredService<YourClass>();
    }
}

0
正如已经评论过的那样,服务定位器模式并不是最好的方法,被认为是一种反模式。 我理解需要找到一种简单的方法将现有代码轻松转换为开箱即用的 DI 系统,而不会让人发疯。 因此,我建议您这样做:

1)Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<DatabaseContext>(
            options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        // other services configuration here

        // IMPORTANT: This should be the last line of ConfigureServices!
        IOC.CurrentProvider = services.BuildServiceProvider();
    }
...

2) IOC.cs

public class IOC
{
    public static IServiceProvider CurrentProvider { get; internal set; }

    public static T resolve<T>()
    {
        return CurrentProvider.GetService<T>();
    }
}

这应该允许您在现有基于Unity的服务定位器代码中使用dotnet core DI,只需进行最少量的修复(基本上只是一些using声明需要被修复),只要您庄严承诺尽快重构代码以摆脱所有Service Locator代码:D


这样做行不通,因为你没有生命周期处理。首先,你将有两个应用程序级别的容器:第一个是在调用Configure之前由ASP.NET Core创建的ConfigureServices方法创建的,第二个是通过services.BuildServiceProvider();创建的应用程序级别容器。从中解析的服务不会在请求结束时被释放。 - Tseng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接