构造函数在Unity容器中注入多个实现

时间:2014-12-19 15:40:09

标签: c# dependency-injection unity-container

对于以下接口和类,如何使用Unity容器流水线(以编程方式)连接它,以便FooController获取ARepository的实例,BarController获取实例BRepository通过构造函数注入?

public interface IRepository
{
}

public class ARepository : IRepository
{
}

public class BRepository : ARepository
{
}

public class FooController
{
    public FooController(IService service, IRepository repository)
    {
    }
}

public class BarController
{
    public BarController(IService service, IRepository repository)
    {
    }
}

5 个答案:

答案 0 :(得分:3)

您可以在注册时通过告知每个控制器注册如何解析其构造函数参数来实现此目的。

container.RegisterType<FooController>(new InjectionConstructor(
    new ResolvedParameter<IService>(), new ResolvedParameter<ARepository>());

container.RegisterType<BarController>(new InjectionConstructor(
    new ResolvedParameter<IService>(), new ResolvedParameter<BRepository>());

答案 1 :(得分:3)

我强烈建议不要为每种类型创建一个专用的/本地/注入的UnityContainer,就像建议的海报之一一样。

可以通过两种方式解决这个问题。

一个是通过 TylerOhlsen 建议明确定义注册时间的解析。 这是一个很好的解决方案,但如果您稍后将 ARepository BRepository 注册为 IRepository 的实现,您仍然需要处理您的事实对于同一个接口有两个实现,如果第三个类有一天需要实现 IRepository ,而没有在注册中专门定义它,它将得到一个不可预测的实例。

第二个选项,更安全,是为 IRepository 注册工厂。 最简单的例子是使用字符串作为键,如下所示:

// Create a resolver(abstract factory) for the IRepository interface type
var resolver = myContainer.Resolve<Func<IRepository>>();

// ... other code here...

// Register mappings for the IRepository interface to appropriate concrete types
myContainer.RegisterType<IRepository, ARepository>("A");
myContainer.RegisterType<IRepository, BRepository>("B");

然后在FooController和BarController的实现中通过注入接收func工厂并选择正确的实例。

public class FooController
{
   IRepository repository;

   public FooController(IService service, Func<IRepository> repositoryFactory)
   {
       repository = repositoryFactory("A");
   }
}

您可以在此处详细了解: http://msdn.microsoft.com/en-us/library/ff660854%28v=pandp.20%29.aspx

答案 2 :(得分:2)

您可以使用名称注册类型,然后在目标类的Dependency属性中使用它:

// Register mappings for the IRepository interface to appropriate concrete types
myContainer.RegisterType<IRepository, ARepository>("A");
myContainer.RegisterType<IRepository, BRepository>("B");

然后在FooController和BarController中,使用Dependency属性声明所需的实现:

public class FooController
{
    public FooController(IService service, [Dependency("A")] IRepository repository)
    {
    }
}

public class BarController
{
    public BarController(IService service, [Dependency("B")] IRepository repository)
    {
    }
}

您可以在public const stringARepository中使用BRepository "A"而不是"B"RegisterType Dependency

答案 3 :(得分:1)

一种可能性是在解析UnityContainer时注册IRepository要解析的特定类型:

IUnityContainer container = new UnityContainer();
container.RegisterType<IRepository, BRepository>(new ContainerControlledLifetimeManager());

使用此取决于您是否需要对在某些上下文中解析的类型进行更精细的控制 - 如果这样做,您可以考虑使用本地IUnityContainer实例并使用RegisterInstance()代替:

//Assumes container is instantiated and already populated with other instances/type mappings.
IUnityContainer childContainer = container.CreateChildContainer();
container.RegisterInstance<IRepository>(new BRepository(), new ContainerControlledLifetimeManager());

答案 4 :(得分:1)

JoefGoldstein 让我一路走来,但在尝试时我遇到了一些错误。

我必须使用命名依赖项注册我的类,并使用InjectionFactory类来解析依赖项。

// register interfaces to implementations with a named dependency 
myContainer.RegisterType<IRepository, ARepository>("A");
myContainer.RegisterType<IRepository, BRepository>("B");

// register Injection factory to resolve the dependency
container.RegisterType<Func<string, IRepository>>(
            new InjectionFactory(c =>
            new Func<string, IRepository>(name => c.Resolve<IRepository>(name)))
);

然后在我的控制器中

public class FooController
{
   IRepository repository;

   public FooController(IService service, Func<string, IRepository> repositoryFactory)
   {
       repository = repositoryFactory("A");
   }
}