繁体   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