【问题标题】:Constructor injection multiple implementations in Unity Container [duplicate]Unity Container中的构造函数注入多个实现[重复]
【发布时间】:2014-12-19 15:40:08
【问题描述】:

对于以下接口和类,我如何使用 Unity Container 流畅地(以编程方式)将其连接起来,以便 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)
    {
    }
}

【问题讨论】:

标签: c# dependency-injection unity-container


【解决方案1】:

您可以在注册时通过告诉每个控制器注册如何解析其构造函数参数来实现这一点。

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

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

【讨论】:

    【解决方案2】:

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

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

    一种方法是按照 TylerOhlsen 的建议专门定义注册时间的解析。 这是一个很好的解决方案,但如果您稍后将 ARepositoryBRepository 都注册为 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

    【讨论】:

      【解决方案3】:

      您可以使用名称注册类型,然后在目标类的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)
          {
          }
      }
      

      您可以在ARepositoryBRepository 中使用public const string,而不是在RegisterTypeDependency 中使用"A""B"

      【讨论】:

      • 如果我们声明依赖于类而不是配置器或其他东西,它不会破坏使用依赖注入的全部目的吗?
      • 该类声明它需要 IService 的特定“风格”,但实际实例化的 IService 类型在运行时解析并取决于类型的注册方式。
      【解决方案4】:

      一种可能是在解析IRepository时注册UnityContainer要解析的具体类型:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多