返回

.NET 依赖注入如何一个接口注册两种实现

2025-04-06 .NET 依赖注入 3389 0

在.NET的依赖注入(Dependency Injection,DI)系统中,一个接口注册两种或多种实现是常见的需求,尤其是在需要根据不同场景或条件选择不同实现时。以下是一些实现方法:

1. 使用 IEnumerable<T> 解析所有实现

这是最常见和推荐的方法。你可以将所有实现都注册到同一个接口,然后在需要的地方通过 IEnumerable<T> 来解析它们。

示例代码:

// 注册实现
services.AddTransient<IMyInterface, MyImplementation1>();
services.AddTransient<IMyInterface, MyImplementation2>();

// 解析实现
public class MyConsumer
{
    private readonly IEnumerable<IMyInterface> _implementations;

    public MyConsumer(IEnumerable<IMyInterface> implementations)
    {
        _implementations = implementations;
    }

    public void DoSomething()
    {
        foreach (var implementation in _implementations)
        {
            implementation.DoWork();
        }
    }
}

优点:清晰地表示了对多个实现的需求。易于扩展,可以随时添加新的实现。

缺点:需要在运行时处理多个实现的选择逻辑。

2. 使用命名的服务

你可以使用命名的服务来区分不同的实现,并在需要时通过名称来解析它们。

// 注册实现
services.AddTransient<IMyInterface, MyImplementation1>("Implementation1");
services.AddTransient<IMyInterface, MyImplementation2>("Implementation2");

// 解析实现
public class MyConsumer
{
    private readonly IServiceProvider _serviceProvider;

    public MyConsumer(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public void DoSomething(string implementationName)
    {
        var implementation = _serviceProvider.GetRequiredService<IMyInterface>(implementationName);
        implementation.DoWork();
    }
}

优点:允许在运行时根据名称选择特定的实现。

缺点:需要在运行时处理名称的传递和选择逻辑。增加代码的复杂度。

3. 使用工厂模式

你可以创建一个工厂类,根据不同的条件返回不同的实现。

 

// 创建工厂接口和实现
public interface IMyInterfaceFactory
{
    IMyInterface Create(string type);
}

public class MyInterfaceFactory : IMyInterfaceFactory
{
    private readonly IServiceProvider _serviceProvider;

    public MyInterfaceFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IMyInterface Create(string type)
    {
        switch (type)
        {
            case "Implementation1":
                return _serviceProvider.GetRequiredService<MyImplementation1>();
            case "Implementation2":
                return _serviceProvider.GetRequiredService<MyImplementation2>();
            default:
                throw new ArgumentException($"Unknown type: {type}");
        }
    }
}

// 注册工厂和实现
services.AddTransient<IMyInterface, MyImplementation1>();
services.AddTransient<IMyInterface, MyImplementation2>();
services.AddTransient<IMyInterfaceFactory, MyInterfaceFactory>();

// 解析实现
public class MyConsumer
{
    private readonly IMyInterfaceFactory _factory;

    public MyConsumer(IMyInterfaceFactory factory)
    {
        _factory = factory;
    }

    public void DoSomething(string type)
    {
        var implementation = _factory.Create(type);
        implementation.DoWork();
    }
}

优点:将选择实现的逻辑封装在工厂类中。使客户端代码更加简洁。

缺点:增加了工厂类的复杂性。

选择哪种实现方式?

选择哪种方法取决于你的具体需求:

  • 如果需要处理所有实现,IEnumerable<T> 是最佳选择。
  • 如果需要在运行时根据名称选择特定的实现,可以使用命名的服务。
  • 如果选择实现的逻辑比较复杂,可以使用工厂模式。
顶部