<C#>在 .NET 开发中,依赖注入, 注册一个接口的多个实现

在 .NET 开发里,有时一个接口会有多个实现类,此时就需要向依赖注入容器注册多个实现。下面会详细介绍不同场景下如何注册多个实现,以及怎样从容器中解析这些实现。

1. 注册多个实现

在 .NET 中,依赖注入容器可以通过不同方式注册同一接口的多个实现。

1.1 以列表形式注册

你可以把同一接口的多个实现添加到一个列表中,然后将这个列表注册到依赖注入容器。

复制代码
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;

// 定义接口
public interface IMessageSender
{
    void SendMessage(string message);
}

// 实现类1
public class EmailSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine($"Sending email: {message}");
    }
}

// 实现类2
public class SmsSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine($"Sending SMS: {message}");
    }
}

class Program
{
    static void Main()
    {
        var services = new ServiceCollection();

        // 注册多个实现
        services.AddTransient<IMessageSender, EmailSender>();
        services.AddTransient<IMessageSender, SmsSender>();

        var serviceProvider = services.BuildServiceProvider();

        // 解析所有实现
        var messageSenders = serviceProvider.GetServices<IMessageSender>();
        foreach (var sender in messageSenders)
        {
            sender.SendMessage("Hello, World!");
        }
    }
}

在上述代码中,EmailSenderSmsSender 都实现了 IMessageSender 接口。通过多次调用 AddTransient 方法,将这两个实现类注册到了依赖注入容器。最后,使用 GetServices<IMessageSender>() 方法可以获取所有实现该接口的实例。

1.2 按名称或键注册

如果你想根据名称或键来区分不同的实现,可以自定义一个字典来管理这些实现。

复制代码
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;

// 定义接口
public interface IMessageSender
{
    void SendMessage(string message);
}

// 实现类1
public class EmailSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine($"Sending email: {message}");
    }
}

// 实现类2
public class SmsSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine($"Sending SMS: {message}");
    }
}

class MessageSenderFactory
{
    private readonly Dictionary<string, Func<IMessageSender>> _senders;

    public MessageSenderFactory(IServiceProvider serviceProvider)
    {
        _senders = new Dictionary<string, Func<IMessageSender>>
        {
            { "Email", () => serviceProvider.GetRequiredService<EmailSender>() },
            { "Sms", () => serviceProvider.GetRequiredService<SmsSender>() }
        };
    }

    public IMessageSender GetSender(string name)
    {
        if (_senders.TryGetValue(name, out var factory))
        {
            return factory();
        }
        throw new ArgumentException($"No sender found with name: {name}");
    }
}

class Program
{
    static void Main()
    {
        var services = new ServiceCollection();

        services.AddTransient<IMessageSender, EmailSender>();
        services.AddTransient<IMessageSender, SmsSender>();
        services.AddTransient<MessageSenderFactory>();

        var serviceProvider = services.BuildServiceProvider();

        var factory = serviceProvider.GetRequiredService<MessageSenderFactory>();
        var emailSender = factory.GetSender("Email");
        emailSender.SendMessage("Hello via email!");

        var smsSender = factory.GetSender("Sms");
        smsSender.SendMessage("Hello via SMS!");
    }
}

在这个例子中,MessageSenderFactory 类负责根据名称来获取不同的 IMessageSender 实现。通过在构造函数中初始化一个字典,将名称与对应的实现关联起来。

2. 解析多个实现

  • 获取所有实现 :使用 GetServices<T>() 方法可以获取注册到容器中的所有 T 类型的实现。如前面第一个示例所示,serviceProvider.GetServices<IMessageSender>() 会返回一个包含所有 IMessageSender 实现的集合。
  • 按名称或键解析 :借助自定义的工厂类(如 MessageSenderFactory),可以根据名称或键来获取特定的实现。

3. 应用场景

  • 插件系统:在插件系统里,不同的插件可能实现了同一个接口。通过注册多个实现,可以方便地管理和使用这些插件。
  • 多渠道消息发送:就像前面的示例,应用程序可能需要通过不同的渠道(如邮件、短信)发送消息,每个渠道对应一个实现类。

总结

在 .NET 开发中,为同一接口注册多个实现是可行的,并且有多种方式可供选择。你可以将多个实现以列表形式注册,也可以按名称或键进行注册。通过不同的解析方式,能够根据需求获取特定的实现。这样可以提高代码的灵活性和可扩展性。

相关推荐
wertyuytrewm27 分钟前
Java 异常|Java Exceptions
java·开发语言
雪碧聊技术36 分钟前
深入理解 Java GC:从“房间清洁工”到解决系统卡顿实战
java·开发语言
大鹏说大话42 分钟前
Java并发编程核心:线程安全、synchronized与volatile的深度剖析
java·开发语言
JAVA+C语言1 小时前
Java IO 流
java·开发语言
酉鬼女又兒1 小时前
零基础快速入门前端CSS Transform 与动画核心知识点及蓝桥杯 Web 应用开发考点解析(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·css·职场和发展·蓝桥杯·html
山川行1 小时前
Python快速闯关8:内置函数
java·开发语言·前端·笔记·python·学习·visual studio
charlie1145141911 小时前
嵌入式C++教程实战之Linux下的单片机编程:从零搭建 STM32 开发工具链(2) —— HAL 库获取、启动文件坑位与目录搭建
linux·开发语言·c++·stm32·单片机·学习·嵌入式
Java基基1 小时前
sdkman 一键切换 JDK 版本管理工具
java·开发语言·sdkman
春日见1 小时前
GIT操作大全(个人开发与公司开发)
开发语言·驱动开发·git·matlab·docker·计算机外设·个人开发
XiYang-DING1 小时前
【Java SE】var关键字
java·开发语言