使用Autofac时,我发现自己写了很多这样的样板代码:
public class MyClass {
[...]
public MyClass(IFoo foo, IBar bar, IBaz baz) {
_foo = foo;
_bar = bar;
_baz = baz;
}
}
是否有一种方法可以根据名称约定(自动映射程序)使用Autofac自动将构造函数注入的依赖项分配给它们的等效成员变量?或者也许您可以使用属性告诉Autofac它应该注入哪些属性,例如:
[DependencyInjected]
private IFoo _foo;
[DependencyInjected]
private IBar _bar;
[DependencyInjected]
private IBaz _baz;
答案 0 :(得分:2)
是否有一种方法可以根据名称约定(自动映射程序)使用Autofac自动将构造函数注入的依赖项分配给它们的等效成员变量?
不,除非你自己建造它。 Autofac仅与标准OOP实践兼容,不包括使用Reflection来填充私有成员变量。
当implementing the Dependency Injection pattern in C#有3种不同的方式可以注入依赖项时:
没有接受模式用于注入private
成员变量。实际上,这不能用标准的OO原则来完成,在.NET中它只能使用Reflection来完成。
此外,在使用依赖注入模式时,没有规则说必须使用DI容器,例如Autofac。实际上,在应用DI图案时,DI容器的使用完全是可选。例如,在进行单元测试时,很容易使用没有Autofac的模式 - 这是一个使用NUnit和Moq的例子。
[Test]
public void TestDoSomething()
{
// Arrange
var foo = new Mock<IFoo>();
var bar = new Mock<IBar>();
var baz = new Mock<IBaz>();
var target = new MyClass(foo.Object, bar.Object, baz.Object);
// Act
var result = target.DoSomething();
// Assert
Assert.IsNotNull(result);
// Test other conditions
}
另一方面,如果你添加这一额外的反射,你需要访问它才能填充你的MyClass
依赖项。
[Test]
public void TestDoSomething()
{
// Arrange
var foo = new Mock<IFoo>();
var bar = new Mock<IBar>();
var baz = new Mock<IBaz>();
var target = new MyClass();
// Use Reflection to insert the dependencies into the object
InjectDependencies(target, foo.Object, bar.Object, baz.Object);
// Act
var result = target.DoSomething();
// Assert
Assert.IsNotNull(result);
// Test other conditions
}
这里的一个重要问题是,如果您完全删除InjectDependencies(target, foo, bar, baz);
行,代码将编译正常,并且您可能会在运行时的某个位置最终得到NullReferenceException
类。 instance constructor的目的是:
在使用新表达式创建类的对象时创建和初始化任何实例成员变量。
这可以保证正确构造对象及其所有依赖项。具有构造函数注入的DI模式的典型示例:
public class MyClass
{
private readonly IFoo _foo;
private readonly IBar _bar;
private readonly IBaz _baz;
public MyClass(IFoo foo, IBar bar, IBaz baz) {
_foo = foo ?? throw new ArgumentNullException(nameof(foo));
_bar = bar ?? throw new ArgumentNullException(nameof(bar));
_baz = baz ?? throw new ArgumentNullException(nameof(baz));
}
}
上面的示例使用构造函数中的 readonly
关键字和保护条款(您的示例中缺少这些)保证 MyClass
的实例无法创建,除非提供了所有依赖项。换句话说,任何成员变量都有{0}的概率为0 {0},因此您不必担心通过向其余成员添加null
检查来增加代码的复杂性。班上的。构造函数之外的任何代码都有0%的可能更改任何依赖项,这可能会导致应用程序难以找到稳定性问题。
最重要的是,如果您想在整个班级中构建自己的Autofac扩展并编写null
检查,那么可以使用Reflection以这种方式填充您的类,但我不会不推荐它,因为你正在使用纯OOP实现松散耦合并将其转换为一个紧密耦合的Reflection代码,所有类(以及使用它们的任何人)都将依赖它根据。
您也正在消除使用C#的便捷功能的可能性,这些功能可以保证实例始终具有所有依赖关系,无论使用它的上下文(DI容器或没有DI容器)并且它们不能是在运行时无意中替换或设置为null
。
如果您对“样板代码”的主要关注是您必须自己键入构造函数代码,那么以下是一些自动执行该部分的Visual Studio扩展:
不幸的是,他们似乎都没有将guard子句添加到构造函数中。