10

Javaではfinal、変数は1回だけ割り当てることができますが、その割り当てはプログラム内のどこでも行うことができることを意味します。C#では、フィールドはコンストラクターreadonlyでのみ割り当てることができることを意味します。これは、IMOではあまり役に立ちません。

ご存知のとおり、C#はJavaの設計に大きく影響されましたが、この違いは常に私を非常に奇妙なものとして困惑させてきました。CLRとJavaの動作があまり役に立たないという技術的な理由があるかどうか誰かが知っていますか?readonlyfinal

編集:

コメントに応えて; 私は不変性の利点をよく知っており、それをあらゆる場所で使用していることを指摘したいと思います。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

作成されたアセンブリのメタデータで:の動作には技術的な理由があります。フィールドは、コンストラクターの外部でフィールドが変更されないようにする属性でマークされてます。1ただし、検証はできませんが、読み取り専用フィールドのアドレスを取得することにより、その値を変更することは可能です。検証可能なILおよびC#では、これを行うことはできません。readonlyinitonly

コンパイラは、メソッドが呼び出される可能性のあるすべての順序を分析する必要があるため、コンパイル時にすべてのメソッドにこれを適用することは不可能です。実行時に、すべてのフィールド書き込みを以前に書き込まれたかどうかをチェックする必要がある場合、CLRに負担がかかり、パフォーマンスが低下する可能性があります。代わりに、C#とCLRでは、コンストラクターの慎重に分析されたスコープを除いて、フィールドに値を割り当てることを許可しない方が安全です。

私の意見では、これによってreadonlyキーワードの価値が低下することはありません。コンストラクターによってのみ値が提供されるフィールド(リストの作成やコンストラクター引数の格納など)には、あらゆる場所で使用します。C#は、その後フィールドを変更しないようにし、誤って設定しnullたりしないようにします。

1)これを指摘してくれたEricLippertに感謝します。

于 2013-02-22T15:03:46.617 に答える
-1

これは古い質問ですが、Java15では機能しないことに注意してください。

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 に答える