const
とstatic readonly
フィールドについて読みました。定数値のみを含むクラスがいくつかあります。システム内のさまざまなものに使用されます。それで、私の観察が正しいかどうか疑問に思います:
この種の定数値は、公開されているすべてのものに対して常にstatic readonly
であるべきですか?そして、内部/保護/非公開の値にのみconst
を使用しますか?
おすすめは何ですか? static readonly
フィールドを使わなくても、むしろプロパティを使うべきです。
public static readonly
フィールドは少し変わっています。 public static
プロパティ(get
name__のみ)はより一般的になります(おそらくprivate static readonly
フィールドに裏付けられています)。
const
name__の値はコールサイトに直接書き込まれます。これは両刃です。
値が 決して 変更されない場合、constは問題ありません - Zero
name__などは妥当なconstを作成します; pそれ以外は、static
name__プロパティがより一般的です。
Consumer が別のアセンブリにある場合は、static readonly
を使用します。 2つの異なるアセンブリにconst
と Consumer を含めることは、 自分で足を撃つための素晴らしい方法です 。
const int a
readonly int a
これは他の答えを補足するものです。私はそれらを繰り返さないでしょう(今4年後)。
const
name__と非constのセマンティクスが異なる場合があります。例えば:
const int y = 42;
static void Main()
{
short x = 42;
Console.WriteLine(x.Equals(y));
}
True
name__を出力します。
static readonly int y = 42;
static void Main()
{
short x = 42;
Console.WriteLine(x.Equals(y));
}
False
name__を書き込みます。
その理由は、メソッド x.Equals
には2つのオーバーロードがあり、1つはshort
name__(System.Int16
)を受け取り、もう1つはobject
name__(System.Object
)を受け取ります。今度の問題は、どちらか一方または両方が私のy
name__引数に適用されるかどうかです。
y
name__がコンパイル時定数(リテラル)の場合、const
name__の場合、int
name__が定数であれば、暗黙の変換fromshort
toint
name__が存在することが重要になります。 C#コンパイラは、その値がshort
name__の範囲内にあることを検証します(これは42
です)。 C#言語仕様の 暗黙の定数式変換 を参照してください。そのため、両方の過負荷を考慮する必要があります。オーバーロードEquals(short)
が優先されます(任意のshort
name__はobject
name__ですが、すべてのobject
name__がshort
name__であるわけではありません)。そのためy
name__はshort
name__に変換され、そのオーバーロードが使用されます。 Equals
name__は、同じ値を持つ2つのshort
name__を比較し、それによってtrue
name__が得られます。
y
name__が定数ではない場合、int
name__からshort
name__への暗黙的変換は存在しません。これは、一般的にint
name__がshort
name__に収まるには大きすぎる可能性があるためです。 (explicit変換は存在しますが、私はEquals((short)y)
とは言わなかったので、関係ありません。)オーバーロードが1つだけ適用されることがわかります、Equals(object)
。そのためy
name__はobject
name__に囲まれています。 Equals
name__はSystem.Int16
とSystem.Int32
を比較しようとしています、そして実行時型が一致しないので、それはfalse
name__をもたらすでしょう。
稀なケースでは、const
name__型のメンバーをstatic readonly
フィールドに変更すると(またはそれが可能な場合は別の方法でも)、プログラムの動作が変わる可能性があると結論します。
注意すべき点は、 const はプリミティブ型/値型に制限されていることです(例外は文字列です)。
readonly
キーワードはconst
キーワードとは異なります。 const
フィールドはフィールドの宣言時にのみ初期化できます。 readonly
フィールドは宣言時またはコンストラクタ内で初期化できます。したがって、readonly
フィールドは、使用されるコンストラクタに応じて異なる値を取ります。また、const
フィールドはコンパイル時定数ですが、readonly
フィールドは実行時定数に使用できます
静的読み取り専用 :値は実行時にstatic
コンストラクタを介して変更できます。しかし、メンバー機能を通してではありません。
定数 :デフォルトではstatic
です。値はどこからも変更できません(Ctor、Function、runtimeなどno-where)。
読み取り専用 :値は実行時にコンストラクタを介して変更できます。しかし、メンバー機能を通してではありません。
あなたは私のレポを見てみることができます: C#のプロパティの種類 。
const
とreadonly
は似ていますが、まったく同じではありません。
const
フィールドはコンパイル時の定数です。つまり、その値はコンパイル時に計算できます。 readonly
フィールドは、型の構築中にコードを実行しなければならないという追加のシナリオを可能にします。構築後、readonly
フィールドは変更できません。
例えば、const
メンバーは以下のようにメンバーを定義するために使用することができます。
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
3.14や0のような値はコンパイル時定数です。ただし、型を定義し、それを作成前のインスタンスをいくつか提供したい場合を考えてください。たとえば、Colorクラスを定義して、黒、白などの一般的な色の「定数」を指定することができます。右側はコンパイル時定数ではないため、constメンバーを使用してこれを行うことはできません。通常の静的メンバでこれを行うことができます。
public class Color
{
public static Color Black = new Color(0, 0, 0);
public static Color White = new Color(255, 255, 255);
public static Color Red = new Color(255, 0, 0);
public static Color Green = new Color(0, 255, 0);
public static Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
しかし、それでは、Colorのクライアントがそれを悪用するのを防ぐことはできません。おそらく、BlackとWhiteの値を入れ替えることによってです。言うまでもありませんが、これはColorクラスの他のクライアントにとっての驚きです。 「読み取り専用」機能はこのシナリオに対応しています。
宣言にreadonly
キーワードを導入するだけで、柔軟な初期化を維持しながら、クライアントコードの誤解を防ぎます。
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
Constメンバーは常に静的であるのに対して、読み取り専用メンバーは静的または非静的のどちらでもかまいません。通常のフィールドとまったく同じです。
これら2つの目的に単一のキーワードを使用することは可能ですが、これはバージョン管理の問題かパフォーマンスの問題のどちらかを引き起こします。しばらくの間、このキーワード(const)に単一のキーワードを使用し、開発者が次のように書いたとします。
public class A
{
public static const C = 0;
}
そして別の開発者がAに依存するコードを書きました。
public class B
{
static void Main() => Console.WriteLine(A.C);
}
さて、生成されるコードはA.Cがコンパイル時定数であるという事実に頼ることができますか?つまり、A.Cの使用は単に値0に置き換えられますか。これに「はい」と言うと、それはAの開発者がA.Cが初期化される方法を変えることができないことを意味します - これは許可なしにAの開発者の手を結ぶ。
この質問に対して「いいえ」と言った場合、重要な最適化は見逃されます。おそらく、Aの作者は、A.Cが常にゼロになるということに肯定的です。 constとreadonlyの両方を使用すると、Aの開発者は意図を指定できます。これにより、バージョン管理動作が改善され、パフォーマンスも向上します。
私が好むのは、可能な限り const を使用することです。上記のように、これはリテラル式または評価を必要としないものに限定されます。
私がその制限に立ち向かうならば、1つ注意を払って static readonly にフォールバックする。 Marcが here に言及しているように、私は一般的にgetterとbacking private static readonly フィールドでpublic staticプロパティを使用します。
Const: Constは "constant"に他なりません。その値はコンパイル時には定数です。そしてそれに値を割り当てることは必須です。デフォルトではconstは静的であり、プログラム全体を通してconst変数の値を変更することはできません。
静的読み取り専用: 静的読み取り専用型変数の値は、実行時に割り当てることも、コンパイル時に割り当てて実行時に変更することもできます。しかし、この変数の値は静的コンストラクタでしか変更できません。それ以上変更することはできません。実行時に一度だけ変更できます
参照: c-sharpcorner
静的読み取り専用フィールドは、後のバージョンで変更される可能性がある値を他のアセンブリに公開する場合に有利です。
たとえば、アセンブリX
が次のように定数を公開するとします。
public const decimal ProgramVersion = 2.3;
Assembly Y
がX
を参照してこの定数を使用する場合、コンパイル時に値2.3がAssembly Y
に焼き付けられます。これは、X
が後で2.4に設定された定数で再コンパイルされた場合でも、Y
が再コンパイルされるまで、Y
は以前の2.3の値を使用します。静的な読み取り専用フィールドはこの問題を回避します。
もう1つの見方は、将来変更される可能性のある値は定義上一定ではないため、1つとして表すべきではないということです。
const:
読み取り専用:
C#.Netでは、constとstaticの読み取り専用フィールドの間に小さな違いがあります。
constはコンパイル時にvalueで初期化されなければなりません。
constはデフォルトでは静的で、後で変更することはできません定数値で初期化する必要があります。すべてのデータ型で使用できるわけではありません。 exTimeTimeの場合。 DateTimeデータ型と一緒に使用することはできません。
public const DateTime dt = DateTime.Today; //throws compilation error
public const string Name = string.Empty; //throws compilation error
public static readonly string Name = string.Empty; //No error, legal
readonlyはstaticとして宣言できますが、必須ではありません。宣言時に初期化する必要はありません。その値はコンストラクタを使って一度割り当てたり変更することができます。そのため、readonlyフィールドの値を1回変更する可能性があります(静的であってもそうでなくても構いません)が、constでは不可能です。
Const :const変数値は宣言と一緒に定義する必要があり、その後は変更されません。constは暗黙的に静的なので、クラスインスタンスを作成しなくてもアクセスできます。 これはコンパイル時に値を持ちます
ReadOnly :宣言時および実行時のコンストラクタの使用時に定義できる読み取り専用の変数値。読み取り専用変数はクラスインスタンスなしでアクセスできません。
静的読み取り専用 :宣言中に静的読み取り専用変数値を定義することはできますが、他のコンストラクターを使用して定義することはできません。
私たちが異なるアセンブリで変数を消費しなければならないならば、静的なreadonlyはより良い選択になるでしょう。下のリンクで完全な詳細をチェックしてください
https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/ /
定数は名前が暗示するようなもので、変化しないフィールドで、通常はコンパイル時にコード内で静的に定義されます。
読み取り専用変数は、特定の条件下で変更される可能性があるフィールドです。
最初に定数のように宣言したときに初期化することもできますが、通常はコンストラクタ内でのオブジェクト構築中に初期化されます。
上記の条件では、初期化が行われた後に変更することはできません。
静的な読み取り専用は、私にとっては不適切な選択のように思えます。静的な場合は変更されないので、public constを使用します。単独または通常の変数です。
また、もう1つの重要な違いは、定数はクラスに属し、読み取り専用変数はインスタンスに属するということです。