const
とreadonly
C#の違いは何ですか?
いつどちらを使用しますか?
の明らかな違いは別として、
const
VS値の定義時に値を宣言するreadonly
必要がありますが、動的に計算できますが、コンストラクターが終了する前に割り当てる必要があります..その後、凍結されます。const
は暗黙的にstatic
. それらにアクセスするには、ClassName.ConstantName
表記法を使用します。微妙な違いがあります。で定義されたクラスを考えてみましょうAssemblyA
。
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly int I_RO_VALUE;
public Const_V_Readonly()
{
I_RO_VALUE = 3;
}
}
AssemblyB
AssemblyA
コードでこれらの値を参照して使用します。これをコンパイルすると:
const
、検索置換のようなものです。AssemblyB
値 2 はの ILに「焼き付けられます」 。これは、明日I_CONST_VALUE
20 に更新した場合、AssemblyB
再コンパイルするまで 2 のままであることを意味します。readonly
値の場合はref
、メモリ ロケーションへのようなものです。AssemblyB
値はの ILに焼き付けられません。これは、メモリ位置が更新された場合、AssemblyB
再コンパイルせずに新しい値を取得することを意味します。したがって、I_RO_VALUE
が 30 に更新された場合は、ビルドするだけで済みAssemblyA
、すべてのクライアントを再コンパイルする必要はありません。したがって、定数の値が変わらないことが確実な場合は、 a を使用しconst
ます。
public const int CM_IN_A_METER = 100;
ただし、変更される可能性のある定数がある場合 (egwrt 精度).. または疑わしい場合は、readonly
.
public readonly float PI = 3.14;
更新: Aku はこれを最初に指摘したため、言及を得る必要があります。また、これを学んだ場所をプラグインする必要があります:効果的な C# - Bill Wagner
const には落とし穴があります。別のアセンブリから定数を参照すると、その値は呼び出し元のアセンブリに直接コンパイルされます。そうすれば、参照先のアセンブリで定数を更新しても、呼び出し元のアセンブリでは変更されません!
追加するreadonly
だけですが、参照型の場合、参照は値ではなく読み取り専用になります。例えば:
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};
public UpdateReadonly()
{
I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
I_RO_VALUE = new char[]{'V'}; //will cause compiler error
}
}
これはそれを説明します。要約: const は宣言時に初期化する必要があり、readonly はコンストラクターで初期化できます (したがって、使用するコンストラクターに応じて異なる値を持ちます)。
編集:微妙な違いについては、上記のギシュの落とし穴を参照してください
const
: どこでも変更できません。
readonly
: この値は、コンストラクターでのみ変更できます。通常の機能では変更できません。
定数メンバーはコンパイル時に定義され、実行時に変更できません。定数は、キーワードを使用してフィールドとして宣言され、宣言const
時に初期化する必要があります。
public class MyClass
{
public const double PI1 = 3.14159;
}
メンバーは、不変のreadonly
値を表すという点で定数に似ています。違いは、readonly
メンバーは実行時にコンストラクターで初期化できることと、宣言時に初期化できることです。
public class MyClass1
{
public readonly double PI2 = 3.14159;
//or
public readonly double PI3;
public MyClass2()
{
PI3 = 3.14159;
}
}
定数
static
(暗黙的に静的です)。読み取り専用
読み取り専用には小さな落とし穴があります。readonly フィールドは、コンストラクター内で複数回設定できます。チェーンされた 2 つの異なるコンストラクターで値が設定されている場合でも、値は許可されます。
public class Sample {
private readonly string ro;
public Sample() {
ro = "set";
}
public Sample(string value) : this() {
ro = value; // this works even though it was set in the no-arg ctor
}
}
const はコンパイル時の定数ですが、 readonly では実行時に値を計算し、コンストラクターまたはフィールド初期化子に設定できます。したがって、「const」は常に一定ですが、「readonly」は割り当てられると読み取り専用になります。
C# チームの Eric Lippert が、さまざまな種類の不変性に関する詳細情報を提供しています。
const がバージョンセーフではない、または参照型に関連していないことを示す別のリンクを次に示します。
まとめ:
読み取り専用: 実行時に Ctor を介して値を変更できます。ただし、メンバー関数経由ではありません
定数: デフォルトでは静的です。値はどこからでも変更できません (Ctor、関数、ランタイムなどどこにもありません)
さらに別の落とし穴: 読み取り専用の値は、リフレクションを介して「不正な」コードによって変更される可能性があります。
var fi = this.GetType()
.BaseType
.GetField("_someField",
BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);
値はすべてのオブジェクトで同じであると思いconst
ます(そしてリテラル式で初期化する必要があります)が、readonly
インスタンス化ごとに異なる場合があります...
これらは両方とも一定ですが、コンパイル時にも定数を使用できます。つまり、違いの1つの側面は、const変数を属性コンストラクターへの入力として使用できるが、読み取り専用変数は使用できないことです。
例:
public static class Text {
public const string ConstDescription = "This can be used.";
public readonly static string ReadonlyDescription = "Cannot be used.";
}
public class Foo
{
[Description(Text.ConstDescription)]
public int BarThatBuilds {
{ get; set; }
}
[Description(Text.ReadOnlyDescription)]
public int BarThatDoesNotBuild {
{ get; set; }
}
}
私たちのオフィスのチーム メンバーの 1 人が、const、static、および readonly をいつ使用するかについて、次のガイダンスを提供しました。
最後に、const フィールドは static ですが、その逆は当てはまりません。
C#.Net の const フィールドと readonly フィールドには顕著な違いがあります。
const はデフォルトで静的であり、後で変更できない定数値で初期化する必要があります。コンストラクターでも値の変更は許可されていません。すべてのデータ型で使用できるわけではありません。ex-DateTime の場合。DateTime データ型では使用できません。
public const DateTime dt = DateTime.Today; //throws compilation error
public const string Name = string.Empty; //throws compilation error
public readonly string Name = string.Empty; //No error, legal
readonly は static として宣言できますが、必須ではありません。宣言時に初期化する必要はありません。その値は、コンストラクターを使用して割り当てまたは変更できます。そのため、インスタンス クラスのメンバーとして使用すると利点があります。2 つの異なるインスタンス化では、読み取り専用フィールドの値が異なる場合があります。例えば -
class A
{
public readonly int Id;
public A(int i)
{
Id = i;
}
}
次に、次のように、読み取り専用フィールドを特定の値で初期化できます。
A objOne = new A(5);
A objTwo = new A(10);
ここで、インスタンス objOne の readonly フィールドの値は 5 になり、objTwo の値は 10 になります。これは、const を使用して行うことはできません。
const とマークされた変数は、厳密に型指定された #define マクロに過ぎず、コンパイル時に const 変数参照はインライン リテラル値に置き換えられます。結果として、特定の組み込みプリミティブ値型のみがこの方法で使用できます。読み取り専用とマークされた変数は、実行時にコンストラクターで設定でき、実行時にも読み取り専用が適用されます。これに関連して若干のパフォーマンス コストが発生しますが、それは、任意の型 (参照型を含む) で readonly を使用できることを意味します。
また、const 変数は本質的に静的ですが、必要に応じて readonly 変数はインスタンス固有にすることができます。
別の落とし穴。
const は実際には基本的なデータ型でのみ機能するため、クラスを操作する場合は、ReadOnly を使用する必要があると感じるかもしれません。ただし、罠に注意!ReadOnly は、オブジェクトを別のオブジェクトに置き換えることができないことを意味します (別のオブジェクトを参照させることはできません)。ただし、オブジェクトへの参照を持つプロセスは、オブジェクト内の値を自由に変更できます。
そのため、ReadOnly はユーザーが変更できないことを意味すると誤解しないでください。C# には、クラスのインスタンス化で内部値が変更されるのを防ぐ単純な構文はありません (私の知る限り)。
Aconst
はハードコーディングする必要があり、asはクラスのコンストラクターで設定readonly
できます。
違いは、静的読み取り専用フィールドの値は実行時に設定されるため、プログラムの実行ごとに異なる値を持つことができることです。ただし、const フィールドの値はコンパイル時の定数に設定されます。
覚えておいてください: 参照型の場合、どちらの場合も (静的とインスタンス)、readonly 修飾子は、フィールドへの新しい参照の割り当てを防止するだけです。特に、参照が指すオブジェクトを不変にするわけではありません。
詳細については、このトピックに関する C# のよく寄せられる質問 ( http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx ) を参照してください。
ReadOnly : 値は、クラスのコンストラクターから 1 回だけ初期化されます。
const: どの関数でも初期化できますが、一度だけです
定数はリテラル値としてコンシューマーにコンパイルされますが、静的文字列は定義された値への参照として機能します。
演習として、外部ライブラリを作成してコンソール アプリケーションで使用し、ライブラリの値を変更して再コンパイルし (コンシューマ プログラムを再コンパイルせずに)、DLL をディレクトリにドロップして EXE を手動で実行します。定数文字列が変更されないこと。
const と readonly は似ていますが、まったく同じではありません。const フィールドはコンパイル時の定数です。つまり、その値はコンパイル時に計算できます。読み取り専用フィールドを使用すると、型の構築中に一部のコードを実行する必要がある追加のシナリオが可能になります。構築後、読み取り専用フィールドは変更できません。
たとえば、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 = r;
green = g;
blue = b;
}
}
しかし、おそらく黒と白の値を交換することによって、色のクライアントがそれをいじるのを防ぐものは何もありません. 言うまでもなく、これは 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 = r;
green = g;
blue = b;
}
}
const メンバーは常に静的であることに注意するのは興味深いことですが、readonly メンバーは、通常のフィールドと同様に、静的であってもなくてもかまいません。
これら 2 つの目的で 1 つのキーワードを使用することは可能ですが、これはバージョン管理の問題またはパフォーマンスの問題につながります。この (const) に 1 つのキーワードを使用し、開発者が次のように記述したと仮定します。
public class A
{
public static const C = 0;
}
別の開発者が A に依存するコードを作成しました。
public class B
{
static void Main() {
Console.WriteLine(A.C);
}
}
さて、生成されたコードは、AC がコンパイル時の定数であるという事実に依存できますか? つまり、AC の使用を単純に値 0 に置き換えることはできますか? これに「はい」と言った場合、それは A の開発者が AC の初期化方法を変更できないことを意味します。つまり、A の開発者は許可なく手を縛られます。この質問に「いいえ」と答えた場合、重要な最適化が見逃されています。おそらく、A の作成者は、AC が常にゼロになることを確信しています。const と readonly の両方を使用すると、A の開発者は意図を指定できます。これにより、バージョン管理の動作が向上し、パフォーマンスも向上します。
主に; const には定数値を割り当てる必要がありますが、静的な読み取り専用フィールドの値を実行時に非定数値に割り当てることができます。
主な違いは、Const が #DEFINE に相当する C であることです。数は文字通りプリコンパイラのように置き換えられます。readonly は実際には変数として扱われます。
この区別は、プロジェクト A がプロジェクト B のパブリック定数に依存している場合に特に関係します。パブリック定数が変更されたとします。const/readonly の選択は、プロジェクト A の動作に影響します。
Const: プロジェクト A は、置換された定数でコンパイルされているため、新しい値をキャッチしません (もちろん、新しい const で再コンパイルされない限り)。
ReadOnly: プロジェクト A は常にプロジェクト B にその変数値を要求するため、B のパブリック定数の新しい値を取得します。
正直なところ、真に普遍的な定数 (Pi、Inches_To_Centimeters など) を除いて、ほぼすべてに対して readonly を使用することをお勧めします。変更される可能性のあるものについては、readonly を使用します。
これが役に立てば幸いです、アラン。
上の人が言ったことに加えて一つ。読み取り専用の値 (例: readonly MaxFooCount = 4; ) を含むアセンブリがある場合、別の値 (例: readonly MaxFooCount = 5;) を持つそのアセンブリの新しいバージョンを出荷することで、呼び出し元のアセンブリが参照する値を変更できます。
ただし、const を使用すると、呼び出し元がコンパイルされるときに、呼び出し元のコードに組み込まれます。
このレベルの C# 習熟度に達している場合は、Bill Wagner の著書『Effective C#: 50 Specific Ways to Improvement Your C#』 (およびその他の 49 項目) を読む準備ができています。