我正在开发一个小的类库,并为我的DI使用Simple Injector。这个类库有一个访问点(我猜是某种服务),它是public,并且它有一些internal服务和存储库。
我看到Simple Injector不支持内部构造函数的构造函数注入。例如,我的产品服务如下所示:
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());当我运行代码时,我得到了以下异常:
For the container to be able to create ProductService, it should contain exactly one public constructor, but it has 0.我的问题:
1)注入内部类在架构/设计方面不起作用有什么特别的原因吗?
2)这种行为(对不应该是公共的类使用依赖注入)是如何实现的,它是所期望的吗?
发布于 2014-02-11 18:17:39
Simple Injector试图给你一个合理的默认值。默认情况下,它仅限于具有单个公共构造函数的自动连接类型,因为它具有multiple constructors is an anti-pattern。Simple Injector默认情况下只注入公共构造函数,因为为了让Simple Injector能够安全地调用类型的构造函数,它必须是公共的。例如,当应用程序在(部分信任)沙箱中运行时,Simple Injector将无法调用内部构造函数,尽管可以在完全信任中调用内部构造函数,但创建此类类型的速度会更慢。为了提高性能,最好将类型和构造函数保持为公共的。
除了这些技术约束之外,在正常情况下,组件及其构造函数将是公共的,因为通常情况下,您将始终拥有需要访问该组件的外部使用者。这类使用者的示例是您的单元测试项目和composition root project。
因此,合理的默认值是“一个公共构造函数”,但类型本身不必是公共的,尽管解析内部类型会更慢,并且在沙箱中可能并不总是有效的。换句话说,当您不在沙箱(如Silverlight或Windows Phone)中运行时,只要内部类型只有一个公共类型,简单注入器就能够解析这些类型
但是,如果您确实需要或希望构造函数是内部的,则可以通过实现和注册自定义IConstructorResolutionBehavior来覆盖构造函数解析行为。下面是一个例子:
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);
}
}此自定义构造函数解析行为可以按如下方式注册:
var container = new Container();
container.Options.ConstructorResolutionBehavior =
new InternalConstructorResolutionBehavior(container);
// Normal registrations herehttps://stackoverflow.com/questions/21696823
复制相似问题