英文:
How can I scan for generic interfaces?
问题
以下是代码的中文翻译部分:
我正在管理不同类型的产品,并从不同的制造商API中获取它们的信息。它们共享一些公共属性,因此我决定将类型定义为泛型:
public class Product<T> where T : class, new() {
public string Name { get; set; } = string.Empty;
public T ProductInfo { get; set; } = new T();
}
我的应用程序将获取一个产品DTO列表,我需要从不同地方检索其详细信息。我决定创建一个每个ProductRetriever
都将实现的接口。我将询问每个ProductRetriever
是否能够检索信息。如果可以,我将调用其Retrieve
方法。
由于每个ProductRetriever
将返回Product<T>
的特定ProductInfo
,我决定将其定义为泛型接口:
public interface IProductRetriever<TProductInfo> where TProductInfo : class, new() {
Task<bool> CanRetrieve(ProductCategoryEnum productCategory);
Task<Product<TProductInfo>?> Retrieve(ProductDto dto);
}
我已经实现了几个ProductRetriever
,我手动一个接一个地调用它们,它们工作正常。例如:
var manufacturerOneRetriever = new ManufacturerOneRetriever<Product1>();
if (manufacturerOneRetriever.CanRetrieve(ProductCategoryEnum.Automotive)) {
var product = manufacturerOneRetriever.Retrieve(productDto);
}
现在,我想要扫描程序集以查找实现IProductRetriever<TProductInfo>
接口的类,并调用它们。
在我有泛型接口之前,我能够扫描程序集并向容器注册ProductRetrievers
:
using IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services => {
var iProductRetrievers = typeof(IProductRetriever).Assembly.GetTypes()
.Where(x => x is { IsAbstract: false, IsClass: true } && x.GetInterface(nameof(IProductRetriever)) == typeof(IProductRetriever));
foreach (var rule in iProductRetrievers) {
services.Add(new ServiceDescriptor(typeof(IProductRetriever), rule, ServiceLifetime.Transient));
}
})
.Build();
现在,我将其定义为泛型接口后,在以下部分的泛型部分x.GetInterface(nameof(IProductRetriever<>))
中出现错误:
.Where(x => x is { IsAbstract: false, IsClass: true } && x.GetInterface(nameof(IProductRetriever<>)) == typeof(IProductRetriever<>))
英文:
I am managing different types of products and I am getting their information from different manufacturers' APIs. They share some common properties, so I decided to make the type be generic:
public class Product<T> where T : class, new() {
public string Name { get; set; } = string.Empty;
public T ProductInfo { get; set; } = new T();
}
My application will be getting a list of productDTOs whose details I will need to retrieve from different places. I decided to create an interface that each ProductRetriever
will implement. I will ask each ProductRetriever
if they can retrieve the information. If it can, I will call its Retrieve
method.
Since each ProductRetriever
will be returning the specific ProductInfo
for the Product<T>
, I decided to make it a generic interface:
public interface IProductRetriever<TProductInfo> where T : class, new() {
Task<bool> CanRetrieve(ProductCategoryEnum productCategory);
Task<Product<TProductInfo>?> Retrieve(ProductDto dto);
}
I've implemented several ProductRetriever
s which I've manually called one at a time and they work fine. For example:
var manufacturerOneRetriever = new ManufacturerOneRetriever<Product1>();
if(manufacturerOneRetriever.CanRetrieve(ProductCategoryEnum.Automotive)) {
var product = manufacturerOneRetriever.Retrieve(productDto);
}
Now, I would like to scan the assembly searching for the classes that implement the IProductRetriever<TProductInfo>
and call them.
Before I had the generic interface, I was able to scan the assembly and register the ProductRetrievers
with the container:
using IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services => {
var iProductRetrievers = typeof(IProductRetriever).Assembly.GetTypes()
.Where(x => x is { IsAbstract: false, IsClass: true } && x.GetInterface(nameof(IProductRetriever)) == typeof(IProductRetriever));
foreach (var rule in iProductRetrievers) {
services.Add(new ServiceDescriptor(typeof(IProductRetriever), rule, ServiceLifetime.Transient));
}
})
.Build();
Now that I have it as a generic interface, I am getting an error in the generic portion of x.GetInterface(nameof(IProductRetriever<>))
in:
.Where(x => x is { IsAbstract: false, IsClass: true } && x.GetInterface(nameof(IProductRetriever<>)) == typeof(IProductRetriever<>))
答案1
得分: 3
从 GetInterface
的文档中:
> 注意
>
> 对于泛型接口,名称参数是已编码的名称,以重音符号(<code>`</code>)结尾,后跟类型参数的数量。这对泛型接口定义和构造的泛型接口都适用。例如,要查找 IExample<T>
或 IExample<string>
,请搜索 <code>"IExample`1"</code>。
与 typeof
不同,nameof
不能用于开放泛型类型,例如 IProductRetriever<>
。即使您传入一个构造类型,它也只会求值为泛型类型的简单名称,而不包括<code>`1</code>部分。
您可以使用字符串文字,或者使用 typeof(IProductRetriever<>).Name
。
还要注意,GetInterface
返回一个构造类型,其中填充了类型参数,因此您不能直接将其与 typeof(IProductRetriever<>)
进行比较。您应该首先获取其泛型类型定义:
x.GetInterface("IProductRetriever`1").GetGenericTypeDefinition() == typeof(IProductRetriever)
我不确定 ServiceDescriptor
如何工作,但如果它也需要构造的泛型类型,您需要再次使用 GetInterface
的返回值。您将传入:
rule.GetType().GetInterface("IProductRetriever`1")
英文:
From the documentation of GetInterface
> Note
>
> For generic interfaces, the name parameter is the mangled name, ending
> with a grave accent (<code>`</code>) and the number of type
> parameters. This is true for both generic interface definitions and
> constructed generic interfaces. For example, to find IExample<T>
or
> IExample<string>
, search for <code>"IExample`1"</code>.
Unlike typeof
, nameof
cannot be used with an open generic type like IProductRetriever<>
. Even if you pass in a constructed type, it will only evaluate to the simple name of the generic type, without the <code>`1</code> part.
You can either use a string literal, or typeof(IProductRetriever<>).Name
instead.
Also note that GetInterface
returns a constructed type, with the type parameters filled in, so you can't directly compare it to typeof(IProductRetriever<>)
. You should get its generic type definition first:
x.GetInterface("IProductRetriever`1").GetGenericTypeDefinition() == typeof(IProductRetriever)
I'm not sure how ServiceDescriptor
works, but if it needs a constructed generic type too, you would need to use the return value of GetInterface
again. You would pass in
rule.GetType().GetInterface("IProductRetriever`1")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论