我2个月前开始使用C#进行开发。从使用Symfony的PHP背景开始,到目前为止,我对依赖注入和爱情泛型都有一定的了解,但是两者的结合目前使我有些困惑。
我想使用工厂来创建IHandler
的特定实例。 IHandler
可以收到一个IParser<T>
,正如您所看到的,它支持泛型,因此我为每个可能的解析器提供了一个接口。工厂将获得具有IParser
方法的SupportsParsing
列表,该方法将在工厂内部调用以获取正确的IParser
并使用所选的IHandler
创建新的IParser
。
public interface IServiceFactory<out T>
{
T Create(string key);
}
public class EventHandlerFactory<T> : IServiceFactory<IHandler>
{
private readonly IEnumerable<IParser<T>> _parsers;
public EventHandlerFactory(IEnumerable<IParser<T>> parsers)
{
_parsers = parsers;
}
public IHandler Create(string key)
{
foreach (IParser<T> parser in _parsers)
{
if (parser.SupportsParsing(key))
{
return new EventHandler<T>(parser);
}
}
throw new NotImplementedException();
}
}
public interface IParser<T>
{
List<T> Parse();
bool SupportsParsing(string key);
}
public class EventCounterParser : IParser<EventCounter>
{
public List<EventCounter> Parse()
{
throw new System.NotImplementedException();
}
public bool SupportsParsing(string key)
{
throw new System.NotImplementedException();
}
}
public class EventLevelParser : IParser<EventLevel>
{
public List<EventLevel> Parse()
{
throw new System.NotImplementedException();
}
public bool SupportsParsing(string key)
{
throw new System.NotImplementedException();
}
}
public interface IHandler
{
void Handle();
}
public class EventHandler<T> : IHandler
{
private readonly IParser<T> _parser;
public EventHandler(IParser<T> parser)
{
_parser = parser;
}
public void Handle()
{
throw new System.NotImplementedException();
}
}
因此注册解析器很容易
services.AddScoped<IParser<EventCounter>, EventCounterParser>();
services.AddScoped<IParser<EventLevel>, EventLevelParser>();
但是我现在想做的是:*注册服务工厂*注册处理程序*自动将所有IParser
实例注入EventHandlerFactory
这就是我越来越难的地方。我真的不知道如何在泛型内部使用泛型时注册服务,以及如何在此处注入泛型IList
或IEnumerable
。
我为IHandler
做的尝试:
services.AddScoped<IHandler, Handler.Event.EventHandler<EventLevelParser>>();
services.AddScoped<IHandler, Handler.Event.EventHandler<EventCounterParser>>();
services.AddScoped(typeof(IServiceFactory<>), typeof(EventHandlerFactory<>));
未处理的异常。 System.AggregateException:无法构造某些服务(验证服务描述符'ServiceType:GenericDITest.Handler.IHandler生存期:范围实现类型:GenericDITest.Handler.Event.EventHa时出错。尝试激活“ GenericDITest.Handler.Event.EventHandler
1[GenericDITest.Parser.Event.EventLevelParser]': Unable to resolve service for type 'GenericDITest.Parser.IParser
1 [GenericDITest.Parser.Event.EventCounterParser]”时,ndler1[GenericDITest.Pa rser.Event.EventLevelParser]'.) (Error while validating the service descriptor 'ServiceType: GenericDITest.Handler.IHandler Lifetime: Scoped ImplementationType: GenericDITest.Handler.Event.EventHandler
1 [GenericDITest.Parser.Event.EventLevelParser]':Unab可以解决类型为'GenericDITest.Parser.IParser1[GenericDITest.Parser.Event.EventCounterParser]' while attempting to activate 'GenericDITest.Handler.Event.EventHandler
1 [GenericDITest.Parser.Event.EventCounterParser]'的服务。)
所以我尝试使用指定类型的注册
services.AddScoped(typeof(IHandler), typeof(Handler.Event.EventHandler<>));
services.AddScoped(typeof(IServiceFactory<>), typeof(EventHandlerFactory<>));
但随后我得到了错误
System.ArgumentException:无法实例化服务类型'GenericDITest.Handler.IHandler'的实现类型'GenericDITest.Handler.Event.EventHandler`1 [T]'。
可悲的是,我对泛型的了解还不足以真正解决此问题。我不太了解错误消息。也许我定义的服务错误?
像建议的@ user1672994一样,我进行了以下更改
IHandler
至IHandler<out T>
EventHandler<T> : IHandler
至EventHandler<T> : IHandler<T>
EventHandlerFactory<T> : IServiceFactory<IHandler>
至EventHandlerFactory<T> : IServiceFactory<IHandler<T>>
public IHandler Create(string key)
至public IHandler<T> Create(string key)
。
现在,我可以将服务添加为services.AddScoped(typeof(IHandler<>), typeof(Handler.Event.EventHandler<>));
,这将立即启动应用程序,而不会出现任何错误,但是由于所有的泛型,我现在还必须像这样注册我的工厂
services.AddScoped(typeof(IServiceFactory<>), typeof(EventHandlerFactory<>));
。
但是当我通过var service = provider.GetService(typeof(IServiceFactory<>));
访问工厂时,出现了新错误。Implementation type 'GenericDITest.Handler.Event.EventHandlerFactory
1 [T]'无法转换为服务类型'GenericDITest.Service.IServiceFactory 1[T]'
。但这是我不明白的,因为它是相同的界面?
我还将该项目上传到文件托管者,因此您可以检出它:https://mega.nz/#!jf51UALL!sbVrGSXoTtfzZLzOl9i7wwa-OC5s3xlhuf_RJuorIQs
EventHandler将获得IParser的任何实现
这不是泛型的工作原理。 IParser<T>
是与某些IParser
完全分开的类型。除非您之间确实有类型层次结构,否则它们是完全无关的。泛型在这里可能会造成混淆,因为泛型实际上并不是真正存在的类型。仅当您应用具体的泛型类型参数时,才存在类型。
所以IParser<EventLevel>
和IParser<EventCounter>
都是实数类型(虽然是完全分开的,并且是[[不相关!),但是这些类型的通用“模板”,即IParser<T>
,不是具体类型。
T
将always
引用完全相同的事物。这基本上是一个常量类型,将在某个时刻插入。因此,您的EventHandlerFactory<T>
可能具有IEnumerable<IParser<T>>
,但是如果您将工厂用作EventHandlerFactory<EventCounter>
,则该类型将具有IEnumerable<IParser<EventCounter>>
。因此,这也是通过依赖项注入解决它时将要寻找的类型。因此它无法获取IParser<EventLevel>
实例,因为这些实例与其所请求的类型无关。EventHandlerFactory<EventCounter>
只会为EventCounter
注入解析器,而不会注入其他解析器(这可能不是您要尝试的)。而且,除了使用该类型还为EventLevel
创建处理程序外,您必须使用类型为EventHandlerFactory<EventLevel>
的
different
工厂(它具有自己的EventLevel
解析器列表)。EventCounterParser
返回EventCounter
对象的列表。如果现在要在事件处理程序中使用该对象,则需要
单独的事件处理程序类型可以分别处理每个结果。否则,您将没有通用信息可在通用事件处理程序中使用。这里正确的解决方案在很大程度上取决于您要对解析器和事件处理程序进行的处理。利用我们掌握的信息很难解决。但是,如果我们忽略解析器的那部分,例如事件处理程序将仅以非通用方式使用解析器,则可以将设置减少到以下内容:
public interface IParser
{
List<object> Parse();
bool SupportsParsing(string key);
}
public class EventHandler : IHandler
{
private readonly IParser _parser;
public EventHandler(IParser parser)
{
_parser = parser;
}
public void Handle()
{ }
}
public class EventHandlerFactory
{
private readonly IEnumerable<IParser> _parsers;
public EventHandlerFactory(IEnumerable<IParser> parsers)
{
_parsers = parsers;
}
public IHandler Create(string key)
{
foreach (var parser in _parsers)
{
if (parser.SupportsParsing(key))
{
return new EventHandler(parser);
}
}
throw new NotImplementedException();
}
}
services.AddScoped<IParser, EventCounterParser>();
services.AddScoped<IParser, EventLevelParser>();
services.AddScoped<EventHandlerFactory>();