在 .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!");}}
}
在上述代碼中,EmailSender
?和?SmsSender
?都實現了?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 開發中,為同一接口注冊多個實現是可行的,并且有多種方式可供選擇。你可以將多個實現以列表形式注冊,也可以按名稱或鍵進行注冊。通過不同的解析方式,能夠根據需求獲取特定的實現。這樣可以提高代碼的靈活性和可擴展性。