。NET依赖关系注入具有依赖于其他通用服务的通用服务

问题描述 投票:1回答:1

简介

我2个月前开始使用C#进行开发。从使用Symfony的PHP背景开始,到目前为止,我对依赖注入和爱情泛型都有一定的了解,但是两者的结合目前使我有些困惑。

概念

我想使用工厂来创建IHandler的特定实例。 IHandler可以收到一个IParser<T>,正如您所看到的,它支持泛型,因此我为每个可能的解析器提供了一个接口。工厂将获得具有IParser方法的SupportsParsing列表,该方法将在工厂内部调用以获取正确的IParser并使用所选的IHandler创建新的IParser

代码

IServiceFactory

public interface IServiceFactory<out T>
{
    T Create(string key);
}

EventHandlerFactory

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();
    }
}

IParser

public interface IParser<T>
{
    List<T> Parse();
    bool SupportsParsing(string key);
}

EventCounterParser

public class EventCounterParser : IParser<EventCounter>
{
    public List<EventCounter> Parse()
    {
        throw new System.NotImplementedException();
    }

    public bool SupportsParsing(string key)
    {
        throw new System.NotImplementedException();
    }
}

EventLevelParser

public class EventLevelParser : IParser<EventLevel>
{
    public List<EventLevel> Parse()
    {
        throw new System.NotImplementedException();
    }

    public bool SupportsParsing(string key)
    {
        throw new System.NotImplementedException();
    }
}

IHandler

public interface IHandler
{
    void Handle();
}

EventHandler

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

这就是我越来越难的地方。我真的不知道如何在泛型内部使用泛型时注册服务,以及如何在此处注入泛型IListIEnumerable

尝试

自己尝试

我为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.EventHandler1[GenericDITest.Parser.Event.EventLevelParser]': Unable to resolve service for type 'GenericDITest.Parser.IParser1 [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.EventHandler1 [GenericDITest.Parser.Event.EventLevelParser]':Unab可以解决类型为'GenericDITest.Parser.IParser1[GenericDITest.Parser.Event.EventCounterParser]' while attempting to activate 'GenericDITest.Handler.Event.EventHandler1 [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一样,我进行了以下更改

IHandlerIHandler<out T>EventHandler<T> : IHandlerEventHandler<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.EventHandlerFactory1 [T]'无法转换为服务类型'GenericDITest.Service.IServiceFactory 1[T]'。但这是我不明白的,因为它是相同的界面?

我还将该项目上传到文件托管者,因此您可以检出它:https://mega.nz/#!jf51UALL!sbVrGSXoTtfzZLzOl9i7wwa-OC5s3xlhuf_RJuorIQs

c# generics .net-core
1个回答
0
投票

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解析器列表)。
对我来说,您还不确定要完成什么工作,特别是因为您的示例中的实现都是空的,但是如果我猜测,我会假设您在这里使用了太多的泛型。因此,从一开始,这些就是我的假设:

    您有多个可以使用不同类型的解析器,但每个解析器只能使用一种类型。
  • 您有一个事件处理程序类型,它使用兼容的解析器来处理某个类型的事件。
  • 您想要一个
  • single
工厂,该工厂允许您获取正确的事件处理程序来处理您的密钥。现在,您的方法存在一个基本问题:解析器返回具体类型的列表,例如您的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>();
© www.soinside.com 2019 - 2024. All rights reserved.