在 Java 中,final
表示一个变量只能被赋值一次,但该赋值可以发生在程序的任何地方。在 C# 中,readonly
表示只能在构造函数 中分配一个字段,在我看来,这明显没那么有用。
众所周知,C# 深受 Java 设计的影响,但这种差异一直让我感到困惑,因为它很奇怪。有谁知道 CLR 中是否存在技术原因,导致 C# 的 readonly
与 Java 的 final
相比没有那么有用的行为?
编辑:
回应评论;我想指出的是,我很清楚不变性的好处,而且我到处都在使用它。我认为 readonly
不如 Java 有用,因为:
public class Foo
{
private readonly int _bar;
Foo()
{
_bar = 5;
}
}
糟糕,我实际上需要在辅助方法中初始化该值!
public class Foo
{
private readonly int _bar;
Foo()
{
initialize()
}
private void initialize()
{
_bar = 5; //Can't compile because of semantics of readonly
}
}
最佳答案
readonly
的行为有一个技术原因:在创建的程序集的元数据中,该字段标有 initonly
属性,该属性将确保该字段未在构造函数外修改。1 然而,虽然无法验证,但通过获取只读字段的地址,仍然可以更改其值。可验证的 IL 和 C# 不允许您这样做。
在编译时,不可能对所有方法强制执行此操作,因为编译器必须分析所有可能的调用方法的顺序。在运行时,如果 CLR 必须检查每个写入的字段是否已被写入,它可能会成为 CLR 的负担并对性能产生负面影响。相反,更安全的做法是,C# 和 CLR 只允许在构造函数的仔分割析范围之外的任何地方为字段赋值。
在我看来,这不会降低 readonly
关键字的值(value)。对于值仅由构造函数提供的字段,我到处都使用它(例如,创建列表或存储构造函数参数)。 C# 将确保我不会再更改该字段,确保我不会意外地将其设置为 null
或任何内容。
1) 感谢 Eric Lippert 指出这一点。
关于C# readonly 与 Java final,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15026924/