如何根据需要的 class 注册依赖项(使用 ASP CORE 中的内置 IOC 容器)

How to register dependencies based on the class they are required from(using built-in IOC-container in ASP CORE)

我正在尝试注册一个接口的不同实现,并根据使用这些实现的 类,某些要通过的实现。

public interface ITest { }
public class Test1 : ITest { } 
public class Test2 : ITest { }

public class DoSmthWhichCurrentlyNeedsTest1
{
    private ITest test;

    public DoSmthWhichCurrentlyNeedsTest1(ITest test)
    {
        this.test = test;
    }
}

public class DoSmthWhichCurrentlyNeedsTest2
{
    private ITest test;

    public DoSmthWhichCurrentlyNeedsTest2(ITest test)
    {
        this.test = test;
    }
}

当前解决方案:

services.AddTransient(x=>new DoSmthWhichCurrentlyNeedsTest1(new Test1()));
services.AddTransient(x=>new DoSmthWhichCurrentlyNeedsTest2(new Test2()));

这很好用,除非你有一个 类 有很多依赖项,其中 "x.GetRequiredService" 应该为构造函数中的每个依赖项调用。

我要找的是这样的:

services.AddTransient<ITest, Test1>
    (/*If ITest is required by DoSmthWhichCurrentlyNeedsTest1*/);
services.AddTransient<ITest, Test2>
    (/*If ITest is required by DoSmthWhichCurrentlyNeedsTest2*/);

有没有其他方法我错过了这个目的?

这是一个像下面这样的工作演示:

1.Interface:

public interface ITest {
    string play();
}

2.implement class:

public class Test1 : ITest
{
    public string play()
    {
        return "111";
    }
}
public class Test2 : ITest
{
    public string play()
    {
        return "222";
    }
}

3.test class:

public class DoSmthWhichCurrentlyNeedsTest1
{
    private IEnumerable<ITest> test;

    public DoSmthWhichCurrentlyNeedsTest1(IEnumerable<ITest> test)
    {
        this.test = test;
    }  
    public string Get()
    {
        var flag = test.FirstOrDefault(h => h.GetType().Name == "Test1");
        var value = flag?.play();
        return value;
    }
}
public class DoSmthWhichCurrentlyNeedsTest2
{
    private IEnumerable<ITest> test;

    public DoSmthWhichCurrentlyNeedsTest2(IEnumerable<ITest> test)
    {
        this.test = test;
    }
    public string Get() 
    {
        var flag = test.FirstOrDefault(h => h.GetType().Name == "Test2");
        var value = flag?.play();
        return value;
    }
}

4.Startup.cs:

services.AddTransient<ITest, Test1>();
services.AddTransient<ITest, Test2>();

5.Result:

This works well unless you have a classes with lots of dependencies, where "x.GetRequiredService" should be called for every dependency in the constructor.

这是 ActivatorUtilities.CreateInstance 的一个很好的用例。这是一个例子:

services.AddTransient(sp =>
    ActivatorUtilities.CreateInstance<DoSmthWhichCurrentlyNeedsTest1>(sp, new Test1()));

ActivatorUtilities.CreateInstance<T> 使用 DI 容器和您传递的任何其他参数的组合创建指定类型的实例(本例中为 DoSmthWhichCurrentlyNeedsTest1)。传入的第一个参数是 IServiceProvider,任何其他参数都用于按类型提供显式值。

在所示示例中,ActivatorUtilities.CreateInstance 将:

  • DoSmthWhichCurrentlyNeedsTest1寻找合适的构造函数并分析其参数。
  • 将可分配类型作为附加参数提供的任何内容与构造函数参数进行匹配。我们提供了一个 Test1 的实例,它可以分配给 ITest,以便在下一步中使用。
  • 通过将参数与您提供的值相匹配来创建 DoSmthWhichCurrentlyNeedsTest1 的实例。对于您未提供的任何内容,它会尝试使用 GetService.
  • 解析 DI 容器中的值

这为您提供了方便,不必担心为 DoSmthWhichCurrentlyNeedsTest1 连接所有 DI 提供的依赖项,同时仍然允许您指定您 关心的那些.