我最近想到了一个案例,我可以将新闻导入器的抽象构建到 .NET DI Contianer 中。
这是我的示例案例。
此类代表新闻源。
public abstract class Source {
public Guid Id {get; set;}
}
这个具体来源是一个 Rss Feed。
public class RssFeed: Source {
public string Url {get; set;}
}
现在我为某些来源的进口商提供了一个通用界面。
public interface ISourceImporter<TSource> where TSource: Source {
Task IEnumerable<Post> ImportAsync(TSource source)
}
以及 RssFeed 源的具体实现
public class RssFeedImporter: ISourceImporter<RssFeed> {
}
将服务注册到 DI 容器中
services.AddSingleton<ISourceImporter<RssFeed>, RssFeedImporter>()
所以主要问题出现在通过ServiceProvider使用服务时。我的命令我想像这样抽象我的源的具体类型。
public Task ImportCommand(Source source) {
ISourceImporter<Source> importer = (ISourceImport<Source>)serviceProvider
.GetRequiredService(typeof(ISourceImporter<>).MakeGenericType(source.GetType()))
var posts = await importer.ImportAsync(source);
}
有没有办法使用 .NET 依赖容器构建该抽象?也许我的结构不适合这个? 我读了一篇关于开放泛型的文章,但这在构建 DI 容器时给我带来了循环依赖。
感谢您的帮助。
您的方法是正确的,但是您面临着在运行时解析开放泛型的问题。但是,有一种方法可以结合使用反射和工厂模式来实现您的目标。
定义工厂接口:创建一个工厂接口,提供根据Source的具体类型创建ISourceImporter实例的方法。
实现工厂:使用反射实现工厂接口,根据Source的具体类型动态解析合适的ISourceImporter实现。
注册工厂:在DI容器中注册工厂。
使用工厂:在您的命令中或任何需要导入新闻的地方,从 DI 容器解析工厂并使用它为给定源创建适当的导入器。
这是一个示例实现:
public interface ISourceImporterFactory
{
ISourceImporter<Source> CreateImporter(Source source);
}
public class SourceImporterFactory : ISourceImporterFactory
{
private readonly IServiceProvider _serviceProvider;
public SourceImporterFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public ISourceImporter<Source> CreateImporter(Source source)
{
Type importerType = typeof(ISourceImporter<>).MakeGenericType(source.GetType());
dynamic importer = _serviceProvider.GetRequiredService(importerType);
return importer;
}
}
// Register the factory in the DI container
services.AddSingleton<ISourceImporterFactory, SourceImporterFactory>();
// Usage in your command or wherever you need to import news
public async Task ImportCommand(Source source)
{
var importerFactory = serviceProvider.GetRequiredService<ISourceImporterFactory>();
var importer = importerFactory.CreateImporter(source);
var posts = await importer.ImportAsync(source);
}
这样,您就可以动态解析给定源类型的适当导入器,而无需开放泛型,也不会在 DI 容器注册期间遇到循环依赖问题。