问题描述
我正在开发一个小型类库,并为我的 DI 使用 Simple Injector.类库有一个访问点(我猜是某种服务),它是 public
并且它有一些 internal
服务和存储库.
I am working on a small class library and using Simple Injector for my DI.The class library has an access point (some sort of a service I guess) which is public
and it has some internal
services and repositories.
我看到 Simple Injector 不支持使用内部构造函数注入构造函数.例如,我的产品服务看起来像:
I saw that Simple Injector does not support constructor injection with internal constructors.For example, my product service looks like:
internal class ProductService : IProductService
{
private IProductRepository _productRepository;
internal ProductService(IProductRepository repository)
{
if (repository == null) throw new ArgumentNullException("repository");
_productRepository = repository;
}
}
还有我的设置:
container.Register<IProductService, ProductService>();
container.Register<IProductRepository>(() => new ProductRepository());
当我运行代码时,出现以下异常:
When I run the code, I get the following exception:
For the container to be able to create ProductService, it should contain exactly one public constructor, but it has 0.
我的问题:
1) 注入内部类在架构/设计方面不起作用是否有特定原因?
1) Is there a specific reason that injecting internal classes doesn't work in terms of architecture/design?
2) 这种行为(对不应该公开的类使用依赖注入)是如何实现的,是否需要?
2) How is this behavior (using dependency injection with classes that should not be public) achieved and is it desired?
推荐答案
Simple Injector 试图给你一个合理的默认值.默认情况下,它仅限于具有单个公共构造函数的自动装配类型,因为具有 多个构造函数是一种反模式.默认情况下,Simple Injector 仅注入公共构造函数,因为 Simple Injector 能够安全地调用类型的构造函数,这必须是公共的.例如,当应用程序在(部分信任)沙箱中运行时,Simple Injector 将无法调用内部构造函数,尽管可以在完全信任的情况下调用内部构造函数,但创建此类类型的速度较慢.为了性能,最好将类型和构造函数保持公开.
Simple Injector tries to give you a sensible default. By default it is limited to auto-wiring types with a single public constructor, since having multiple constructors is an anti-pattern. Simple Injector by default only injects into public constructors, since for Simple Injector to be able to safely call a constructor of a type, this must be public. For instance, Simple Injector will not be able to call an internal constructor when the application is running in a (partial trust) sandbox, and although invoking internal constructors is possible in full trust, creating such type is slower. For performance it is best to keep the type and the constructor public.
除了这些技术限制之外,在正常情况下,组件及其构造函数将是公开的,因为您通常总是有需要访问该组件的外部使用者.此类消费者的示例是您的单元测试项目和您的 组合根项目.
Besides these technical constraints, under normal conditions components and their constructors will be public, because you would normally always have external consumers that need to access that component. Examples of such consumers are your unit test projects and your composition root project.
因此明智的默认设置是一个公共构造函数",但类型本身不必是公共的,尽管解析内部类型会更慢并且可能并不总是在沙箱中工作.换句话说,当您不在沙箱(例如 Silverlight 或 Windows Phone)中运行时,Simple Injector 将能够解析内部类型,只要它们具有单个 public 构造函数.
So the sensible default is 'one public constructor', but the type itself doesn't have to be public, although resolving internal types will be slower and might not always work in a sandbox. In other words, when you're not running in a sandbox (such as Silverlight or Windows Phone), Simple Injector will be able to resolve internal types, as long as they have a single public constructor.
但是,如果您确实需要或希望您的构造函数是内部构造函数,则可以通过实现和注册自定义 IConstructorResolutionBehavior
来覆盖构造函数解析行为.举个例子:
But if you really need or want your constructors to be internal, the constructor resolution behavior can be overridden by implementing and registering a custom IConstructorResolutionBehavior
. Here's an example:
public class InternalConstructorResolutionBehavior : IConstructorResolutionBehavior
{
private IConstructorResolutionBehavior original;
public InternalConstructorResolutionBehavior(Container container) {
this.original = container.Options.ConstructorResolutionBehavior;
}
public ConstructorInfo GetConstructor(Type implementationType) {
if (!implementationType.GetConstructors().Any()) {
var internalCtors = implementationType.GetConstructors(
BindingFlags.Instance | BindingFlags.NonPublic)
.Where(c => !c.IsPrivate)
.ToArray();
if (internalCtors.Length == 1) return internalCtors.First();
}
return this.original.GetConstructor(implementationType);
}
}
这个自定义构造函数解析行为可以注册如下:
This custom constructor resolution behavior can be registered as follows:
var container = new Container();
container.Options.ConstructorResolutionBehavior =
new InternalConstructorResolutionBehavior(container);
// Normal registrations here
这篇关于简单的注入器和内部构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!