简体   繁体   English

在Unity中解析类型时传递构造函数参数:最佳实践

[英]Passing constructor parameters when resolving types in Unity: Best practice

It's sometimes necessary when using dependency injection to provide the parameters to use in the constructor. 当使用依赖注入来提供在构造函数中使用的参数时,有时是必要的。 This is something that's supported in Unity (and other dependency injection containers), so that when it tries to create an instance of the type, it can provide your arguments as parameters in the constructor. 这是Unity(以及其他依赖注入容器)支持的内容,因此当它尝试创建该类型的实例时,它可以将您的参数作为参数提供给构造函数。

My question is: is this approach desirable? 我的问题是:这种方法是否可取?

Within an interface it is not possible to specify which parameters an implementing class must have. 在接口内,无法指定实现类必须具有的参数。 By specifying the parameters to Unity, you are assuming that the implementing class has these parameters, and you are placing implicit constraints over future implementing classes. 通过为Unity指定参数,您假设实现类具有这些参数,并且您将对未来的实现类放置隐式约束。 These constraints cannot be communicated through the interface. 这些约束不能通过接口传递。

So, is this is flaw in how interfaces themselves are specified (in .NET), eg. 那么,这是如何指定接口本身(在.NET中)的缺陷,例如。 should it be possible to specify constructor signatures? 应该可以指定构造函数签名吗? Or has this feature (of being able to provide constructor parameters) been included in Unity due to some other need? 或者由于某些其他需要,Unity中是否包含此功能(能够提供构造函数参数)?

The only real workable approach (to me) seems to be use a factory to create the implementing classes, and do dependency injection on the factory. 唯一真正可行的方法(对我来说)似乎是使用工厂来创建实现类,并在工厂上进行依赖注入。

I appreciate my question here might not be clear, so I'll ask it slightly differently: what's the best way to do dependency injection on a class which has a constructor requiring parameters? 我很感激我的问题可能不太清楚,所以我会稍微区别一点:在具有构造函数需要参数的类上进行依赖注入的最佳方法是什么?

(I do not believe this question to be subjective, as there should probably be a single design pattern for this type of dependency injection.) (我不认为这个问题是主观的,因为这种类型的依赖注入可能只有一个设计模式。)

EDIT: 编辑:

I should add, that my main problem is that I may create a new implementing class which has additional constructor parameters (where the constructor parameters are not things that can be created by unity). 我应该补充一点,我的主要问题是我可以创建一个新的实现类,它具有额外的构造函数参数(其中构造函数参数不是可以由unity创建的东西)。

I'm not sure where you got the idea that constructor injection does not fit with DI. 我不知道你在哪里认为构造函数注入不适合DI。 I'd say that the real situation is the opposite of that: constructor injection is one of the most common patterns utilised to achieve dependency injection - I'd go as far as saying that it is the most common pattern, and that view is certainly backed up by the fact that that majority of Inversion of Control containers (DI containers) use constructor injection as their preferred mechanism. 我想说,真正的情况是相反:构造函数注入是用来实现依赖注入最常见的模式之一-我会去远的话说,这是最常见模式,这种观点肯定是由于大多数控制反转容器(DI容器)使用构造函数注入作为其首选机制这一事实得到了支持。

StructureMap for example has a core, very specific support for constructor injection where it will pick the constructor with the most parameters as the constructor used for dependency resolution. 例如,StructureMap具有核心的,非常具体的构造函数注入支持,它将选择具有最多参数的构造函数作为用于依赖项解析的构造函数。

What you are saying by using the constructor injection pattern is that "I am removing the hard coded dependencies within my class by specifying them as parameters passed into the constructor - my class cannot be instantiated without these dependencies". 你通过使用构造函数注入模式说的是“我通过将它们指定为传递给构造函数的参数来删除我的类中的硬编码依赖项 - 我的类在没有这些依赖项的情况下无法实例化”。 Of course, the first half of that statement is the essence of DI, but the second half enforces this more. 当然,该声明的前半部分是DI的本质,但是后半部分更强调了这一点。

Dependencies are an implementation detail that should be able to be changed easily, providing a flexible, loosely coupled solution. 依赖关系是一个应该能够轻松更改的实现细节,提供灵活,松散耦合的解决方案。 They are about the how, not the what. 他们是关于如何,而不是什么。 Interfaces specify the what. 接口指定了什么。 So I'd say that your suggestion of specifying dependencies in interfaces actually goes against the concept of dependency injection. 所以我要说你在接口中指定依赖关系的建议实际上违背了依赖注入的概念。

And as far as your statement about factories - this is exactly what IOC containers are - great big factories that take care of a solution's dependency tree, so you don't need to care. 至于你关于工厂的陈述 - 这正是IOC容器所代表的 - 伟大的大工厂负责解决方案的依赖树,所以你不需要关心。

Edit 编辑

I think maybe you are asking about the case where you want to provide a non-dependency constructor parameter, such as an id for a referenced entity, or an initial state enum? 我想也许您在询问是否要提供非依赖构造函数参数的情况,例如引用实体的id或初始状态枚举?

I personally don't see a problem with an IOC container allowing for this. 我个人认为IOC容器没有问题。 It is still initial state of your class and hence the rules for the creation of that state need to be explicitly expressed. 它仍然是你的类的初始状态,因此需要明确表达创建该状态的规则。 It can mean that you sometimes need more references to your IOC container that you might like, but it is not a horrible enough situation to abandon the other benefits of counstructor injection. 这可能意味着您有时需要更多您可能喜欢的IOC容器的引用,但放弃counstructor注入的其他好处并不是一个非常可怕的情况。

The responsibility of IoC containers (say Unity) is to connect interfaces with concrete implementations. IoC容器(比如Unity)的职责是将接口与具体实现连接起来。 That means your container must know the interface and how to create the object that implements the interface. 这意味着您的容器必须知道接口以及如何创建实现接口的对象。 Using constructor injection is perfectly legal and the recommended way. 使用构造函数注入是完全合法的,也是推荐的方法。 Unity will create the concrete implementation when your application requests an interface through the Resolve() method. 当您的应用程序通过Resolve()方法请求接口时,Unity将创建具体实现。 The Unity container itself is the factory that creates your objects, you use Unity because you don't want to implement those factories by yourself. Unity容器本身是创建对象的工厂,您使用Unity是因为您不想自己实现这些工厂。

The issue here is the definition of the InjectionConstructor in Unity vs say the one in Castle.Windsor. 这里的问题是Unity中的InjectionConstructor的定义vs Castle.Windsor中的定义。

In Unity, if you need to inject a particular parameter, say an AppSetting you are also forced to supply all the other parameters thus fixing the signature of the constructor. 在Unity中,如果需要注入特定参数,比如AppSetting,您还必须提供所有其他参数,从而修复构造函数的签名。 However, in Castle.Windsor it takes the parameter you've supplied and then uses the resolution mechanism to locate the other paramaters in the normal way. 但是,在Castle.Windsor中,它采用您提供的参数,然后使用解析机制以正常方式定位其他参数。

It would be possible to introduce this into Unity by writing a custom Builder strategy that did a "best-fit" approach to which constructor to use rather than the default greedy/supply everything which is the default. 可以通过编写一个自定义构建器策略将其引入Unity,该策略使用构造函数使用“最适合”的方法而不是默认的贪婪/提供默认的所有内容。

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

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