メンバー変数を読み取り専用として宣言する利点は何ですか?クラスのライフサイクル中に誰かが値を変更するのを防ぐだけですか、このキーワードを使用すると速度や効率が向上しますか?
readonly
構造タイプのフィールドは、任意のメンバーの呼び出し以来、単純に変異していない可変フィールドと比較してパフォーマンスのペナルティを課すreadonly
フィールドのコピーを作成するために、コンパイラが発生します値型のフィールドと呼び出しをその上のメンバー。
メンバー変数を読み取り専用として宣言する利点は何ですか?クラスのライフサイクル中に誰かが値を変更するのを防ぐだけですか、このキーワードを使用すると速度や効率が向上しますか?
readonly
構造タイプのフィールドは、任意のメンバーの呼び出し以来、単純に変異していない可変フィールドと比較してパフォーマンスのペナルティを課すreadonly
フィールドのコピーを作成するために、コンパイラが発生します値型のフィールドと呼び出しをその上のメンバー。
回答:
読み取り専用フィールドを使用することによるパフォーマンスの向上はないと思います。これは、オブジェクトが完全に構築されると、そのフィールドが新しい値を指すことができないことを確認するためのチェックです。
ただし、「読み取り専用」は、CLRによって実行時に適用されるため、他のタイプの読み取り専用セマンティクスとは大きく異なります。readonlyキーワードは、CLRによって検証可能な.initonlyにコンパイルされます。
このキーワードの本当の利点は、不変のデータ構造を生成することです。定義による不変のデータ構造は、いったん構築すると変更できません。これにより、実行時の構造の動作を非常に簡単に推論できます。たとえば、不変構造をコードの別のランダムな部分に渡す危険はありません。彼らはこれを変更することはできませんので、その構造に対して確実にプログラムできます。
ここでは不変性のメリットの1程度の良いエントリは次のとおりです。スレッディング
を使用しても明らかなパフォーマンス上の利点はありません。readonly
少なくとも、どこかで言及したことのないものはありません。それは、あなたが提案したとおりに行うためであり、初期化された後の変更を防ぐためです。
したがって、より堅牢で読みやすいコードを作成するのに役立つという利点があります。このようなことの真のメリットは、チームで作業しているときやメンテナンスのためにあるときに得られます。何かを宣言することreadonly
は、コード内でのその変数の使用法についてのコントラクトを置くことに似ています。internal
またはのような他のキーワードと同じ方法でドキュメントを追加すると考えてprivate
ください。「この変数は初期化後に変更してはなりません」と言っているだけでなく、強制しています。
したがって、クラスを作成し、一部のメンバー変数readonly
を設計でマークすると、自分または他のチームメンバーが後でクラスを拡張または変更するときに間違いを犯すのを防ぐことができます。私の意見では、それは価値のあるメリットです(コメントでdoofledorferが言及しているように、余分な言語の複雑さを少し犠牲にしてください)。
非常に実用的に言えば、
dll Aでconstを使用し、dll Bがそのconstを参照している場合、そのconstの値はdll Bにコンパイルされます。dllAをそのconstの新しい値で再デプロイしても、dll Bは元の値を使用します。
DLL Aで読み取り専用を使用し、DLL Bがその読み取り専用を参照する場合、その読み取り専用は実行時に常に検索されます。つまり、その読み取り専用の新しい値でdll Aを再デプロイすると、dll Bはその新しい値を使用します。
readonly
ます。実行時に計算された値をフィールドに格納する機能です。IDを変更せずにコンパイル時に他のアセンブリへの参照などの非値のものをベイクできないためnew object();
、a const
をa に格納することはできません。
コンパイラーがreadonlyキーワードの存在に基づいてパフォーマンスを最適化できる可能性があります。
これは、読み取り専用フィールドもstaticとしてマークされている場合にのみ適用されます。その場合、JITコンパイラーは、この静的フィールドは決して変更されないと想定できます。JITコンパイラは、クラスのメソッドをコンパイルするときにこれを考慮に入れることができます。
典型的な例:クラスには、コンストラクターで初期化される静的な読み取り専用のIsDebugLoggingEnabledフィールドが含まれている可能性があります(構成ファイルに基づくなど)。実際のメソッドがJITコンパイルされると、デバッグログが有効になっていない場合、コンパイラはコードのすべての部分を省略できます。
この最適化が現在のバージョンのJITコンパイラに実際に実装されているかどうかは確認していません。そのため、これは単なる推測にすぎません。
readonlyは値自体にのみ適用されるため、参照タイプを使用している場合、readonlyは参照が変更されるのを防ぐだけであることに注意してください。インスタンスの状態は読み取り専用で保護されていません。
params readonly
を使用して、コンストラクターの外部でフィールドを設定するための回避策があることを忘れないでくださいout
。
少し乱雑ですが:
private readonly int _someNumber;
private readonly string _someText;
public MyClass(int someNumber) : this(data, null)
{ }
public MyClass(int someNumber, string someText)
{
Initialise(out _someNumber, someNumber, out _someText, someText);
}
private void Initialise(out int _someNumber, int someNumber, out string _someText, string someText)
{
//some logic
}
ここでさらに議論する:http : //www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx
out
...
驚いたことに、Jon Skeetが彼のNoda Timeライブラリをテストしているときに見つけたように、readonlyは実際にはコードが遅くなる可能性があります。この場合、20秒で実行されたテストは、読み取り専用を削除してから4秒しかかかりませんでした。
readonly struct
C#7.2のタイプである場合、フィールドを非読み取り専用にする利点はなくなります。
この質問に答えるために基本的な側面を追加します:
プロパティは、set
演算子を省略することで読み取り専用として表現できます。したがって、ほとんどの場合readonly
、プロパティにキーワードを追加する必要はありません。
public int Foo { get; } // a readonly property
それとは対照的にreadonly
、同様の効果を達成するには、フィールドにキーワードが必要です。
public readonly int Foo; // a readonly field
したがって、フィールドをマークすることの利点の1つは、演算子なしでreadonly
プロパティと同様の書き込み保護レベルを達成できることset
です。何らかの理由でフィールドをプロパティに変更する必要がない場合です。
プライベートな読み取り専用配列には注意してください。これらがオブジェクトとしてクライアントを公開している場合(私が行ったように、COM相互運用機能に対してこれを行う可能性があります)、クライアントは配列値を操作できます。配列をオブジェクトとして返す場合は、Clone()メソッドを使用します。
ReadOnlyCollection<T>
配列の代わりに公開します。
ImmutableArray<T>
。これにより、インターフェイスへのボックス化(IReadOnlyList<T>
)またはクラスでのラッピング()が回避されますReadOnlyCollection
。:それは、ネイティブ配列に匹敵する性能を持っているblogs.msdn.microsoft.com/dotnet/2013/06/24/...
読み取り専用マーキングの使用のもう1つの興味深い部分は、フィールドをシングルトンでの初期化から保護することです。
たとえばcsharpindepthからのコードでは:
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton()
{
}
}
readonlyは、フィールドシングルトンが2回初期化されるのを防ぐ役割を果たします。別の詳細では、前述のシナリオでは、constはコンパイル時に強制的に作成されるため、constを使用できませんが、シングルトンは実行時に作成されます。
readonly
宣言時に初期化するか、コンストラクタからのみその値を取得できます。const
それとは異なり、初期化と宣言を同時に行う必要があります。
readonly
すべてのもの const
に加えて、コンストラクタの初期化があります
using System;
class MainClass {
public static void Main (string[] args) {
Console.WriteLine(new Test().c);
Console.WriteLine(new Test("Constructor").c);
Console.WriteLine(new Test().ChangeC()); //Error A readonly field
// `MainClass.Test.c' cannot be assigned to (except in a constructor or a
// variable initializer)
}
public class Test {
public readonly string c = "Hello World";
public Test() {
}
public Test(string val) {
c = val;
}
public string ChangeC() {
c = "Method";
return c ;
}
}
}