簡體   English   中英

使用autofac鍵控服務在運行時基於通用接口解析類型

[英]Resolving type based on Generic Interface at runtime with autofac keyed services

我發現了一些與我面臨的問題相似的問題和回答; 但我還沒能把一個有效的解決方案拼湊起來。

我有以下內容:

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

其中TaskRequestTaskResponse是抽象基類

這個具體類也定義了:

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

基於論壇中的相關主題,基本建議是定義工廠並將其注冊到容器,然后在運行時使用工廠根據提供的參數創建我需要的對象。 這似乎是正確的。

我也看到了相關的建議,即在IIndex<K,V>使用IIndex<K,V>功能來按鍵查找相應的類型/服務。

我無法通過鍵注冊和解析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中的co&contravariance,我將界面更改為:

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

但這只是在沒有很好理解的情況下猜測。 在我的天真視圖中,MathProcessor是一種IProcessing,但似乎並非如此。

我不認為這種類型的注冊是可能的,但是,鑒於您似乎以通用方式調用實際處理,我假設您的主要目標是為每種類型的請求實現離散處理器。

在這種情況下,您可以通過創建BaseProcessing<TV,TW>類型輕微修改模型。 例如:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM