我的项目使用IoC和DI。
然而,我想知道拥有以下内容是否是一种好的做法:
private readonly IMyService myservice;
作为类内的字段,该字段是服务的使用者。该字段是在构造函数中设置的。
我确信我在某个地方见过这个,而且我已经学会了。然而,我也看到:
private IMyService myservice;
这似乎就足够了。为注入的服务接口设置只读字段有什么用途吗?优点是什么?
它是一个接口这一事实无关紧要。在字段上应用readonly
修饰符可以防止您(或其他人)在构造对象后更改其值。它只能在构造函数中分配。
我认为readonly
关键字的使用是构造函数注入正确实现的核心部分。
public class MyClass
{
private readonly IMyService myservice;
public MyClass(IMyService myservice)
{
if (myservice == null)
{
throw new ArgumentNullException("myservice");
}
this.myservice = myservice;
}
}
readonly
关键字和Guard子句在技术上都不需要来实现构造函数注入。然而,它们都有助于增强类的不变量。这就是封装的意义所在。
readonly
字段表示只能在ctor中写入。一旦完成,引用就不能更改或销毁。它对于初始化状态和增强不变性非常有用。
在字段上具有readonly
的优点是它清楚地声明了字段在包含实例的生存期内不会更改。在许多场景中,这使得对给定方法的行为进行推理变得更容易。例如
void Method() {
var marker = myservice.StartOperation();
try {
SomeOtherMethod();
} finally {
myservice.StopOperation(marker);
}
}
假设StartOperation
和StopOperation
是必须在给定的IMyService
实例上成对调用的方法。当myservice
是readonly
字段时,您只能查看此函数,并对满足此合同有高度的信心。
但是,如果它不是readonly
,您必须立即怀疑SomeOtherMethod
和从该函数传递调用的其他所有方法。如果其中任何一个可以突然重置myservice
字段,那么您将违反合同,并最终出现一些非常微妙的错误。
这是readonly关键字的文档。
当应用于类中的字段时,readonly
向读取器指示"此字段在该实例的生存期内不会更改。"这对于依赖关系是非常有用的信息,在构造函数中接收到依赖关系后,这些依赖关系不会更改。
更改依赖项的错误尝试会导致编译时错误,提醒您或其他正在修改类的人,注入的依赖项不应更改。这是一种更容易检测和修复的情况,而不是省略readonly
关键字,然后因为重新分配而不得不追踪错误。
简言之,是的,如果在构建对象后不更改readonly
,那么声明它是一种很好的做法,因为这将防止所有未来的作者犯这个错误。