具有以下接口(interface)及其实现...
public interface IEmpty<T> { }
public class Empty1 : IEmpty<Empty1>{ }
public class Empty2 : IEmpty<Empty2>{ }
public class EmptyN : IEmpty<EmptyN>{ }
允许我注册它们并将它们显式注入(inject)到构造函数中
public class NewClass1 {
private IEmpty<Empty1> Empty;
public NewClass1(IEmpty<Empty1> empty)
{
Empty = empty;
}
public string EmptyType => $"{Empty.GetType()}";
}
但是当我尝试立即解决“IEmpty<>”的所有实现时...
var allIEmpties = host.Services.GetServices(typeof(IEmpty<>));
allIEmpties.ToList().ForEach(empty => Console.WriteLine(empty.GetType()));
...代码的执行抛出了“NotSupportedException”(无法创建开放类型的数组),我有点理解,但让我想知道是否可以完成以及如何完成才能获得处理所有实现 IEmpty 的服务。
有人知道如何实现这一目标吗?
我让这项工作发挥作用的动机是
- 每个服务仅注册一次(DRY)
- 能够将服务显式注入(inject)构造函数,而不需要某些解析器模式或命名依赖项
- 启动后加载所有实现,以验证由于接口(interface)而需要实现的特定属性,而无需反射(reflection)性地搜索所有程序集,这是我的临时解决方案,但爬过一盒针来找到 2 个特定的针听起来是错误的,如果我可以有一个分类盒,让我可以直接取用我需要的针……
使用这些额外的 nuget 包:
- Microsoft.Extensions.DependencyInjection
- Microsoft.Extensions.Hosting
- Microsoft.Extensions.Hosting.Abstractions
我在 LinqPad 中创建了这个概念验证片段,以防您想尝试一下:
void Main()
{
var args = new List<string>();
var host = CreateHostBuilder(args.ToArray()).Build();
var newClass = host.Services.GetService<NewClass1>();
Console.WriteLine(newClass.EmptyType);
var oneEmpty = host.Services.GetService(typeof(IEmpty<Empty2>));
Console.WriteLine(oneEmpty.GetType());
var allIEmpties = host.Services.GetServices(typeof(IEmpty<>));
allIEmpties.ToList().ForEach(empty => Console.WriteLine(empty.GetType()));
}
IHostBuilder CreateHostBuilder(string[] args)
{
var hostBuilder =
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) => {
builder.SetBasePath(Directory.GetCurrentDirectory());
})
.ConfigureServices((context, services) => {
services.AddTransient<IEmpty<Empty1>, Empty1>();
services.AddTransient<IEmpty<Empty2>, Empty2>();
services.AddTransient<IEmpty<EmptyN>, EmptyN>();
services.AddTransient<NewClass1>();
});
return hostBuilder;
}
public class NewClass1 {
private IEmpty<Empty1> Empty;
public NewClass1(IEmpty<Empty1> empty)
{
Empty = empty;
}
public string EmptyType => $"{Empty.GetType()}";
}
public interface IEmpty<T> {}
public class Empty1 : IEmpty<Empty1>{ }
public class Empty2 : IEmpty<Empty2>{ }
public class EmptyN : IEmpty<EmptyN>{ }
最佳答案
通过调用 GetServices(typeof(IEmpty<>))
根据其开放泛型定义解析泛型类型列表MS.DI 不支持。尽管技术上可行,但我所熟悉的 DI 容器中并没有真正支持此功能的。
有很多可能的方法可以解决您的问题。例如,您可以引入一个非泛型 IEmpty
(标记)接口(interface) IEmpty<T>
继承自。
您还可以使用反射浏览代码库,正如您已经提到的,或者您可以浏览 ServiceCollection
中的注册。获取所有注册IEmpty<T>
注册。然后可以使用该列表来获取列表。例如:
var emptyTypes =
from s in services
where s.ServiceType.IsGenericType
where s.ServiceType.GetGenericTypeDefinition() == typeof(IEmpty<>)
select s.ServiceType;
foreach (Type emptyType in emptyTypes)
{
var empty = host.Services.GetRequiredService(emptyType);
Console.WriteLine(empty.GetType());
}
关于c# - 我可以在 C# 中解析带有 'GetServices(typeof(IEmpty<>))' 的开放类型泛型服务集合吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73645572/