簡體   English   中英

使用Autofac解析構造函數中的通用IEnumerable

[英]Resolve IEnumerable of a generic in constructor with Autofac

所以我有一個抽象的工廠類,我的想法是在這個工廠的構造函數中,我將從autofac傳遞一個我感興趣的所有注冊服務的IEnumerable 。這個工廠中有一個傳遞參數的方法,並且代碼將遍歷IEnumerable並返回匹配的服務。 簡單的餡餅,抽象的工廠模式。

問題是,我最近在工廠返回的界面中引入了一個泛型類型,我不知道如何編寫構造函數,因此autofac知道仍然返回所有已注冊的服務,並且基本上忽略了泛型。

一些代碼:

我的界面:

public interface IRunnerServices<in T>
{
    void Create(T entity);
}

接口的一些實現

public class RunnerServiceA : IRunnerServices<A>
{
    public void Create(A entity);
}

public class RunnerServiceB : IRunnerServices<B>
{
    public void Create(B entity);
}

public class RunnerServiceC : IRunnerServices<C>
{
    public void Create(C entity);
}

// Many, many more...

在我的作品根目錄中,我注冊了這樣的服務

builder.RegisterType<RunnerServicesA>().As<IRunnerServices<A>>();
builder.RegisterType<RunnerServicesB>().As<IRunnerServices<B>>();
builder.RegisterType<RunnerServicesC>().As<IRunnerServices<C>>();

而且你知道,A,B,C都是從同一個基類繼承而來的

public class A : LetterBase
{ }

public class B : LetterBase
{ }

public class C : LetterBase
{ }

現在,我的抽象工廠

public class RunnerServicesFactory
{
    private readonly IEnumerable<IRunnerServices<????>> _candidates;
    public RunnerServicesFactory(IEnumerable<IRunnerServices<????>> candidates)
    {
        _candidates = candidates;
    }

    public IRunnerServices<????> Create(int discriminator)
    {
        return _candidates.First(c => c.Discriminator == discriminator);
    }
}

問題在於我在上面的構造函數和其他聲明中提供了什么? 讓autofac知道它應該傳遞這個通用的所有注冊服務?

我試過這個,但沒有運氣,因為autofac沒有通過任何東西

IEnumerable<IRunnerServices<LetterBase>>

為了將RunnerServiceA實現IRunnerService<LetterBase> RunnerServiceAIRunnerService<LetterBase>您需要使用out generic關鍵字修飾符使IRunnerService<T>協變,這是不可能的,因為您有一個接受T參數的方法。

.net不允許您將RunnerServiceAIRunnerService<LetterBase>您可以嘗試執行以下簡單代碼:

var runnerService = (IRunnerServices<LetterBase>)new RunnerServiceA();
// Throws an InvalidCastException 

一種可能的解決方案是使IRunnerService<T>協變,如下所示:

public interface IRunnerServices<out T>
    where T : LetterBase
{
    void Create(LetterBase entity);
}

通過這樣做,您將能夠將RunnerServiceAIRunnerService<LetterBase>並執行以下代碼:

IEnumerable<IRunnerServices<LetterBase>> runners = new IRunnerServices<LetterBase>[] {
                                                        new RunnerServiceA(),
                                                        new RunnerServiceB()
                                                    };

然后,如果RunnerService注冊為IRunnerServices<LetterBase> Autofac將能夠解析IEnumerable<IRunnerServices<LetterBase>>

順便說一下你在做什么讓我想到IIndex<TKey, T>

public class RunnerServicesFactory
{
    private readonly IIndex<Char, IRunnerServices<LetterBase>> _candidates;
    public RunnerServicesFactory(IIndex<Char, IRunnerServices<LetterBase>> candidates)
    {
        _candidates = candidates;
    }

    public IRunnerServices<LetterBase> Create(Char discriminator)
    {
        return _candidates[discriminator];
    }
}

注冊將是這樣的:

builder.RegisterType<RunnerServiceA>().Keyed<IRunnerServices<LetterBase>>('A');
builder.RegisterType<RunnerServiceB>().Keyed<IRunnerServices<LetterBase>>('B');
builder.RegisterType<RunnerServiceC>().Keyed<IRunnerServices<LetterBase>>('C');

暫無
暫無

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

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