2014-12-19 33 views
7

对于下列接口和类,我该如何使用Unity容器来流利地(编程式)连线,以便FooController获得ARepository的实例,并且BarController通过构造器注入获取BRepository的实例?Unity容器中的构造器注入多个实现

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) 
    { 
    } 
} 
+0

DUP的问题看起来不同,但得到的答复是完全一样的。 – jgauffin

+0

这里是另一个答案的工作原理:http://stackoverflow.com/questions/4989676/injecting-a-specific-instance-of-an-interface-using-autofac – jgauffin

回答

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

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

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

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

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

这可以通过两种方式来解决。

一个是通过特别定义注册时间的解析为TylerOhlsen建议。 这是一个很好的解决方案,但如果你注册后都ARepositoryBRepository实现IRepository,你仍然需要对付你有两个implenetations为同一接口的事实,如果第三类将总有一天需要执行IR知识库,而没有专门在注册中对其进行定义,它将得到一个不可预测的实例。

第二个选项稍微安全一点就是注册工厂IR库。 最简单的例子是使用字符串作为键,这样的:

// 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

你可以用一个名字注册的类型,然后使用在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) 
    { 
    } 
} 

您可以使用ARepository两个RegisterTypeDependency一个public const stringBRepository,而不是"A""B"

+1

不是它击败了使用依赖注入如果我们声明依赖于类而不是确认器或类似的东西? – Ruchan

+1

该类声明它需要特定的IService“风味”,但实例化的实际IService类型在运行时解析,并取决于类型的注册方式。 – PeteB

0

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