简体   繁体   English

使用Unity创建实现给定接口的类的实例时如何设置给定属性

[英]How to set a given property when an instance of a class which implements a given interface is created using Unity

Given this simplified scenario: 在这种简化的情况下:

public interface IRepository
{
    string ConnectionString { get; set; }
}

public abstract class Repository : IRepository
{
    public string ConnectionString { get; set; }
}

public class CustomerRepository : Repository, ICustomerRepository
{
}

public class OrderRepository : Repository, IOrderRepository
{
}

and the following Unity registrations: 以及以下Unity注册:

IUnityContainer container = new UnityContainer();
container.RegisterType<ICustomerRepository, CustomerRepository>();
container.RegisterType<IOrderRepository, OrderRepository>();

What is the recommended way to intercept the creation of any IRepository instance in order to set the value for the ConnectionString property (and by extension any other property). 为了设置ConnectionString属性的值(以及扩展为其他属性的值),建议什么方法来拦截任何IRepository实例的创建。

UPDATE 1: This post is not about design patters or an alternate solution involving re-factoring of the original classes. 更新1:这篇文章与设计模式或涉及重构原始类的替代解决方案无关。 It's about Unity and the best way to set a property by intercepting the creation of instances implementing a given interface. 这是关于Unity以及通过拦截实现给定接口的实例的创建来设置属性的最佳方法。

If you make the connectionString a constructor parameter the configuration looks like this 如果将connectionString用作构造函数参数,则配置如下所示

container.RegisterType<ICustomerRepository, CustomerRepository>(new InjectionConstructor("myConnStr1");

For property injection the configuration is 对于属性注入,配置为

container.RegisterType<IOrderRepository, OrderRepository>(new InjectionProperty("ConnectionString", "myConnStr2");

[Update] The TecX project on codeplex contains a port of the Castle Windsor Typed Factory Facilities . [更新] Codeplex上TecX项目包含温莎城堡类型工厂设施的端口。 It allows you to register a factory interface that takes parameters. 它允许您注册带有参数的工厂接口。

public interface ICustomerRepositoryFactory
{
  ICustomerRepository Create(string connectionString);
}

container.RegisterType<ICustomerRepositoryFactory>(new TypedFactory());
container.RegisterType<ICustomerRepository, CustomerRepository>(new InjectionProperty("ConnectionString");

If you resolve the factory interface and call the Create method it will map the method parameter to the according constructor parameter. 如果解析工厂接口并调用Create方法,它将把方法参数映射到相应的构造函数参数。 [Update2] It does not yet support property injection (yet. ask again tomorrow) . [Update2] 它尚不支持属性注入(但请明天再问) It also supports property injection but you will have to mark the property for injection when you register your repository types. 它还支持属性注入,但是在注册存储库类型时,您将必须标记要注入的属性。 [/Update2] You will not have to implement the factory. [/ Update2]您不必实现工厂。 The extension does that for you. 该扩展程序可以为您完成此任务。

Since you need connection strings coming from differnt providers (as you mentioned in your comment). 由于您需要来自不同提供商的连接字符串(如您在评论中所述)。 I would suggest a slight change to the design, you can add a new dependency such as IConnectionStringProvider 我建议对设计进行一些更改,您可以添加一个新的依赖项,例如IConnectionStringProvider

public interface IConnectionStringProvider 
{
    string GetConnectionString(); 
}

Then update IRepository 然后更新IRepository

public interface IRepository  
{    
        IConnectionStringProvider ConnectionStringProvider  {get; set;}
        string ConnectionString { get; } // no set is required 
 }

public abstract class Repository : IRepository     
   {       
         IConnectionStringProvider ConnectionStringProvider  {get; set;}
         public string ConnectionString 
           { 
              get 
                 {
                    return ConnectionStringProvider.GetConnectionString(); 
                 }
            }
   }    

Then you can use unity to inject the right connection string provider per your need 然后,您可以根据需要使用unity注入正确的连接字符串提供程序

container.RegisterType<IConnectionStringProvider , ConnectionStringProvider>();

Your repositories should not be responsible of creating the connection. 您的存储库不应该负责创建连接。

  1. You are breaking Single Responsibility Principle 您违反了单一责任原则
  2. You got duplicated code = harder to maintain the code in the future. 您获得重复的代码=将来很难维护代码。
  3. What do you do if you want to share a connection between your repositories? 如果要共享存储库之间的连接,该怎么办?

Solution: 解:

Create an IConnectionFactory (which implementation you can register as an instance/singleton) and use that as an dependency in your repositories. 创建一个IConnectionFactory (可以将其注册为实例/单例实现),并将其用作存储库中的依赖项。

Update 1 更新1

You can use InjectionProperty . 您可以使用InjectionProperty Lookup the connection string on the line before you configure it. 在配置之前,先在行上查找连接字符串。

Update 2: 更新2:

Use factories to configure the repositories: http://www.pnpguidance.net/post/RegisteringFactoryMethodCreateObjectsUnityStaticFactoryExtension.aspx 使用工厂来配置存储库: http : //www.pnpguidance.net/post/RegisteringFactoryMethodCreateObjectsUnityStaticFactoryExtension.aspx

Something like: 就像是:

container.Configure<IStaticFactoryConfiguration>()
    .RegisterFactory<ICustomerRepository>
    (new FactoryDelegate(c => 
       { 
          var repos = new CustomerRepository();
          repos.ConnectionString = yourComPlus.ConnectionString;
          return repos;
       }
    ));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM