10

在 Java 中,final意味着一个变量只能被分配一次,但该分配可以发生在程序的任何地方。在 C# 中,readonly意味着只能在构造函数中分配字段,而 IMO 的用处明显减少。

众所周知,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
    }     
}
4

2 回答 2

20

行为有一个技术原因readonly:在创建的程序集的元数据中,该字段被标记为属性,该initonly属性将确保该字段不会在构造函数之外被修改。1然而,虽然无法验证,但通过获取只读字段的地址,仍然可以更改其值。可验证的 IL 和 C# 不允许您这样做。

在编译时不可能对所有方法强制执行此操作,因为编译器必须分析调用方法的所有可能顺序。在运行时,如果它必须检查每个字段写入是否之前已写入,则可能会对 CLR 造成负担并对性能产生负面影响。相反,C# 和 CLR 只是不允许在任何地方为字段赋值,除非在构造函数的仔细分析范围内。

在我看来,这并没有readonly降低关键字的价值。对于仅由构造函数提供值的字段(例如创建列表或存储构造函数参数),我到处都使用它。C# 将确保我不会再更改该字段,确保我不会意外地将其设置为null或任何东西。

1 ) 感谢 Eric Lippert 指出这一点。

于 2013-02-22T15:03:46.617 回答
-1

这是一个老问题,但我认为值得注意的是,这在 Java 15 中不起作用

public class Main
{
   final int testInt;

   public Main()
   {
      init();
   }

   private void init() 
   {
      testInt = 3;
   }
}

java:变量testInt未在默认构造函数中初始化

所以看起来 C#readonly和 Javafinal的行为方式相同。

于 2021-03-30T17:53:38.753 回答