.NET Core 泛型服务(依赖于其他泛型服务)的依赖注入

问题

.NET Dependency Injection with generic services that depend on other generic services

概念

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

代码

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<>));
Unhandled exception. System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: GenericDITest.Handler.IHandler Lifetime: Scoped ImplementationType: GenericDITest.Handler.Event.EventHa ndler1[GenericDITest.Parser.Event.EventLevelParser]': Unable to resolve service for type 'GenericDITest.Parser.IParser1[GenericDITest.Parser.Event.EventLevelParser]' while attempting to activate 'GenericDITest.Handler.Event.EventHandler1[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.EventCounterParser]': Unab le to resolve service for type '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: Cannot instantiate implementation type 'GenericDITest.Handler.Event.EventHandler`1[T]' for service type 'GenericDITest.Handler.IHandler'.

答案

但这不是泛型的工作方式。 IParser<T> 是与某些 IParser 完全不同的类型。 除非您实际上在它们之间有类型层次结构,否则它们是完全不相关的。 泛型在这里可能有点令人困惑,因为泛型类型实际上并不是真正存在的类型。 只有当你应用一个具体的泛型类型参数时,才会有一个类型。

因此,IParser<EventLevel>IParser<EventCounter> 都是真实类型(虽然完全独立且不相关!),但这些类型的通用“模板”IParser<T> 不是具体类型。

The EventHandler shall get ANY implementation of IParser

您还必须了解,在泛型类中,泛型类型参数 T 将始终引用完全相同的事物。 这基本上是一个将在某个时候插入的常量类型。

因此,您的 EventHandlerFactory<T> 可能有一个 IEnumerable<IParser<T>>,但如果您将工厂用作 EventHandlerFactory<EventCounter>,那么该类型将有一个 IEnumerable<IParser<EventCounter>>。 所以这也是它在通过依赖注入解析它时要寻找的类型。 因此它无法获取 IParser<EventLevel> 实例,因为这些实例与它所要求的类型无关。

EventHandlerFactory<EventCounter> 只会为 EventCounter 注入解析器,而不会为其他解析器注入解析器(这可能不是您想要做的)。 而不是使用该类型也为 EventLevel 创建处理程序,您将不得不使用 EventHandlerFactory<EventLevel> 类型的不同工厂(它有自己的 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>();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值