依赖关系注入 - 何时使用属性注入

本文关键字:注入 属性 何时使 关系 依赖 | 更新日期: 2023-09-27 18:31:06

我有一个类,它有一个这样的构造函数:

    private string _someString;
    private ObjectA _objectA;
    private ObjectB _objectB;
    private Dictionary<Enum, long?> _dictionaryA;
    private Dictionary<Tuple<Enum,long?>, long?> _dictionaryB; 
    public SomeDiClass(string someString)
    {
        _someString = someString;
        _objectA = new ObjectA();
        _objectB = new ObjectB();
        _dictionaryA = new Dictionary<Enum, long?>();
        _dictionaryB = new Dictionary<Tuple<Enum, long?>, long?>();
    }

我想从这个构造函数中获取依赖项创建。在第一步中,我将 ObjectA 和 B 依赖项移动到构造函数参数,以通过构造函数注入注入它们。我想为此目的使用 IoC 容器,这就是我目前坚持的地方。问题是如何处理someString和字典。我需要将它们注入到类中,因为字典的内容将是单元测试的重要组成部分。通过属性注入注入字符串和字典是个好主意(我在其他类中不需要它们),所以我最终会得到这样的东西吗?

    private ObjectA _objectA;
    private ObjectB _objectB;
    public string SomeString { get; set; }
    public Dictionary<Enum, long?> DictionaryA { get; set; }
    public Dictionary<Tuple<Enum, long?>, long?> DictionaryB { get; set; }
    public SomeDiClass(ObjectA objectA, ObjectB objectB)
    {
        _objectA = objectA;
        _objectB = objectB;
    }

有没有解决这样的事情的最佳实践?

依赖关系注入 - 何时使用属性注入

依赖注入不是最终目标,而是一组特定问题的解决方案。例如,依赖注入可以轻松替换单元测试的抽象,并使应用程序更加灵活,因为您可以交换、修饰和拦截依赖关系,而无需更改消费类。对依赖注入的很好的介绍可以在我合著的《依赖注入原则、实践和模式》(DIPP&P)一书的第1章中找到。

这并不意味着你应该注入一个类具有的每个依赖项,因为它必须帮助你使类更易于测试,系统更易于维护。因此,您必须问自己,从测试的角度来看,从外部注入这些字典是否有帮助,或者它是否有助于使您的应用程序更加灵活。为了很好地掌握要注入什么以及不注入什么,你应该了解易失性和稳定依赖关系的概念,这些概念可以在DIPP&P第1章的第1.3节中阅读。

从测试或可维护性的角度来看,它是否有帮助是一个很难回答的问题,因为您的问题没有足够的细节。但这里有一些提示:

通常唯一希望注入到类中的是服务和配置值。

  • 服务是提供"服务"的某种契约/抽象/接口。这通常意味着该服务将代表您执行某些操作,例如计算价格、与数据库通信、缓存值、返回系统时间或格式化硬盘驱动器:)

  • 配置值就是它本来的样子;只是一个值。但是你需要注入它——它不能硬编码到类中,并且你不希望类从ConfigurationManager中获取值本身,例如,因为这会创建一个隐藏的依赖关系(在Configurationmanager上),这将使类更难测试。

其他内容,如基元、消息、DTO、集合类型和实体,以及不提供任何服务(业务逻辑)且不妨碍单元测试的任何其他内容,不必抽象,因此不必注入(实际上不应通过构造函数或属性注入)。在您的例子中,字典是SomeDiClass类内部状态的一部分,而不是您的类所依赖的服务。

另一方面,如果这些词典被其他服务重用,则必须注入这些词典。但是你永远不想直接注入这样的字典本身,因为字典本身不是服务。相反,您需要围绕它们创建一个抽象;隐藏该字典的详细信息并为应用程序提供围绕它的服务的东西。

当类型的对象创建不受控制时,应使用属性注入(或 setter 注入)。像aspx Page,HttpHandler,ApiController等。对于所有其他情况,建议使用构造函数注入。

为了使用 StructureMap 解析 aspx Page 的依赖关系,我使用以下方法。

首先,我创建一个 BasePage 类,并在构造函数中使用 StructureMap 的 BuildUp() 方法来解析派生页面的依赖关系。代码给出如下:

public class BasePage : Page
{
    public BasePage()
    {
        // instruct StructureMap to resolve dependencies
        ObjectFactory.BuildUp(this);
    }
}
public class Default : BasePage
{
     public ICustomerService customerService { get; set; }
     protected void Page_Load(object sender, EventArgs e)
     {
         // can start using customerService
     }
}
public class Login : BasePage
{
     public IAuthenticationService authenticationService { get; set; }
     protected void Page_Load(object sender, EventArgs e)
     {
         // can start using authenticationService
     }
}