【问题标题】:Resolving type based on Generic Interface at runtime with autofac keyed services使用 autofac 键控服务在运行时基于通用接口解析类型
【发布时间】:2012-11-22 20:11:20
【问题描述】:

我发现了许多与我所面临的问题类似的问题和回答;但我无法拼凑出一个可行的解决方案。

我有以下几点:

public interface IProcessing<V,W> where W: TaskResponse where V: TaskRequest
    {
         W process(V req);
    }

TaskRequest & TaskResponse 是抽象基类

也定义了这个具体的类:

public class MathProcessor : IProcessing<MathRequest, MathResponse>
    {
         public MathResponse process(MathRequest req) {
            // do stuff
            // create a MathResponse instance

            return resp;
        }
    }

其中MathRequestMathResponse 是派生类,各自的抽象类用作接口定义中的约束。

根据接口注册具体类型并使用autofac解析即可。
但是,在运行时尝试基于另一种类型(在本例中为请求对象,例如MathRequest)解析具体类型的预期用途出现了困难。这基本上是为了实现常见的消息处理程序模式(以下是伪代码),其中接收消息并将其分派到适当的处理程序:

TaskRequest req = getNextRequest();

var proc = container.Resolve(req.getType().Name)

proc.process(req);

基于论坛中的相关主题,基本建议是定义一个工厂并将其注册到容器中,然后在运行时使用该工厂根据提供的参数创建我需要的对象。这似乎是对的。

我还看到了相关建议,即使用 autofac 中的 IIndex&lt;K,V&gt; 功能按键查找适当的类型/服务。

我在注册和解析MathProcessor 类型时遇到问题,其中键是一种类型(在本例中为MathRequest)。该错误可能与通用接口定义和允许的内容更相关。

注册:

builder.RegisterType<MathProcessor>().As<IProcessing<MathRequest, MathResponse>>().Keyed<IProcessing<MathRequest, MathResponse>>(strTypeName);

没问题,但是

builder.RegisterType<MathProcessor>().As<IProcessing<TaskRequest, TaskResponse >>().Keyed<IProcessing< TaskRequest, TaskResponse >>(strTypeName);

不是。

注意:基于 .Net 中关于泛型类型和协变的所有帖子,我将接口更改为:

public interface IProcessing<in V, out W> where W: TaskResponse where V: TaskRequest
    {
         W process(V req);
    }

但这只是猜测,没有很好的理解。在我的幼稚观点中,MathProcessor 是 IProcessing 的一种,但似乎并非如此。

【问题讨论】:

    标签: c# generics runtime autofac


    【解决方案1】:

    我认为这种类型的注册是不可能的,但是,鉴于您似乎是以通用方式调用实际处理,我认为您的主要目标是为每种类型的请求实现离散处理器。

    在这种情况下,您可以通过创建 BaseProcessing&lt;TV,TW&gt; 类型来稍微修改您的模型。 例如:

    public abstract class BaseProcessing<TV, TW> : IProcessing
        where TV : TaskRequest
        where TW : TaskResponse
    {
        protected abstract TW DoProcess(TV req);
    
        public TaskResponse Process(TaskRequest req)
        {
            return DoProcess((TV)req);
        }
    }
    

    它实现了一个非常基本的IProcessing 接口,也就是我们将在 AutoFac 中注册的接口:

    public interface IProcessing
    {
        TaskResponse Process(TaskRequest req);
    }
    

    以此为基础,您仍然可以创建处理器,例如:

    public class MathProcessor : BaseProcessing<MathRequest, MathResponse>
    {
        protected override MathResponse DoProcess(MathRequest req)
        {
            return new MathResponse();
        }
    }
    

    其中一种注册方式可能是使用密钥服务,例如:

    builder.RegisterType<MathProcessor>().AsImplementedInterfaces().Keyed<IProcessing>(typeof(MathRequest));
    builder.RegisterType<OtherProcessor>().AsImplementedInterfaces().Keyed<IProcessing>(typeof(OtherRequest));
    

    在这种情况下,我实际上并没有使用类型的名称,而是使用类型本身,但两者都可以。

    现在,拥有键控注册意味着您可以让另一个组件将其作为依赖项使用:

    public class SomeConsumer : IConsumer
    {
        private readonly IIndex<Type, IProcessing> _processors;
    
        public SomeConsumer(IIndex<Type, IProcessing> processors)
        {
            _processors = processors;
        }
    
        public void DoStuff()
        {
            var someRequest = new MathRequest();
            var someResponse = _processors[someRequest.GetType()].Process(someRequest);
        }
    }
    

    【讨论】:

    • 哇!这在 6 年后仍然适用,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    • 2021-09-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-31
    相关资源
    最近更新 更多