C# IServiceProvider依赖注入:多IAnimal实现实例获取问题
问题描述
使用微软依赖注入扩展实现DI,创建了一个.NET 6控制台程序测试。定义了IAnimal接口,以及Dog和Cat两个实现类。通过AddTransient<IAnimal, Dog>()和AddTransient<IAnimal, Cat>()注册服务后,调用GetRequiredService<IAnimal>()仅返回最后注册的Cat实例,请问如何按需获取Dog或Cat实例?
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); builder.Services.AddTransient<IAnimal, Dog>(); builder.Services.AddTransient<IAnimal, Cat>(); using IHost host = builder.Build(); var myobject = GetAnimalObject(host.Services, "Scope 1"); Console.WriteLine($"Name: {myobject.name}"); await host.RunAsync(); static IAnimal GetAnimalObject(IServiceProvider services, string scope) { using IServiceScope serviceScope = services.CreateScope(); IServiceProvider provider = serviceScope.ServiceProvider; var result = provider.GetRequiredService<IAnimal>(); return result; } public sealed class Dog : IAnimal { public string name { get; set; } = "Daug"; } public sealed class Cat : IAnimal { public string name { get; set; } = "Kate"; } public interface IAnimal { string name { get; set; } }
解决方案
方法1:直接请求具体实现类型
如果需求是明确获取Dog或Cat实例,可以直接通过具体类型从服务容器中获取,无需通过IAnimal接口。修改GetAnimalObject方法,增加参数指定要获取的实例类型:
// 修改调用处,指定要获取的类型 var dog = GetAnimalObject(host.Services, "Scope 1", typeof(Dog)); Console.WriteLine($"Name: {dog.name}"); var cat = GetAnimalObject(host.Services, "Scope 1", typeof(Cat)); Console.WriteLine($"Name: {cat.name}"); static IAnimal GetAnimalObject(IServiceProvider services, string scope, Type animalType) { using IServiceScope serviceScope = services.CreateScope(); IServiceProvider provider = serviceScope.ServiceProvider; // 根据具体类型获取实例 return (IAnimal)provider.GetRequiredService(animalType); }
方法2:自定义工厂类封装实例获取逻辑
如果需要通过标识(如字符串)动态获取实例,可以创建一个工厂类,统一处理实例的创建逻辑:
// 新增工厂类 public class AnimalFactory { private readonly IServiceProvider _serviceProvider; public AnimalFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IAnimal GetAnimal(string animalType) { return animalType switch { "Dog" => _serviceProvider.GetRequiredService<Dog>(), "Cat" => _serviceProvider.GetRequiredService<Cat>(), _ => throw new ArgumentException("不支持的动物类型") }; } } // 修改服务注册 builder.Services.AddTransient<Dog>(); builder.Services.AddTransient<Cat>(); builder.Services.AddTransient<AnimalFactory>(); // 修改调用逻辑 using IHost host = builder.Build(); var factory = host.Services.GetRequiredService<AnimalFactory>(); var dog = factory.GetAnimal("Dog"); Console.WriteLine($"Name: {dog.name}"); var cat = factory.GetAnimal("Cat"); Console.WriteLine($"Name: {cat.name}");
方法3:获取所有实现并筛选
可以通过GetServices<IAnimal>()获取所有注册的IAnimal实例,再根据类型或自定义属性筛选目标实例:
static IAnimal GetAnimalObject(IServiceProvider services, string scope, Type targetType) { using IServiceScope serviceScope = services.CreateScope(); IServiceProvider provider = serviceScope.ServiceProvider; // 获取所有IAnimal实例,筛选出目标类型 return provider.GetServices<IAnimal>().FirstOrDefault(a => a.GetType() == targetType) ?? throw new InvalidOperationException("未找到指定类型的实例"); } // 调用示例 var dog = GetAnimalObject(host.Services, "Scope 1", typeof(Dog)); Console.WriteLine($"Name: {dog.name}");
内容的提问来源于stack exchange,提问作者Xinwei Chen
相关产品推荐
相关产品推荐

