使用 Autofac 解析构造函数中泛型的 IEnumerable

本文关键字:泛型 IEnumerable 构造函数 Autofac 使用 | 更新日期: 2024-10-29 18:59:50

所以我有一个抽象的工厂类,这个想法是在这个工厂的构造函数中,我将从 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>>

使用 Autofac 解析构造函数中泛型的 IEnumerable

为了

RunnerServiceA实现转换为IRunnerService<LetterBase>,您需要使用 out 泛型关键字修饰符进行协变IRunnerService<T>这是不可能的,因为您有一个接受T参数的方法。

.net 不允许你RunnerServiceA强制转换为IRunnerService<LetterBase>你可以尝试通过执行以下简单的代码:

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

一种可能的解决方案是使IRunnerService<T>协变如下所示:

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

通过这样做,您将能够将RunnerServiceA转换为IRunnerService<LetterBase>并执行以下代码:

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

然后,Autofac 将能够解析IEnumerable<IRunnerServices<LetterBase>>如果RunnerService被注册为 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');