回答:
の明らかな違いは別として
const
VS readonly
値の定義時に値を宣言する必要がある場合、動的に計算できますが、コンストラクターが終了する前に割り当てる必要があります。その後、凍結されます。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
値が、それは、find-replaceは、値2「に焼き」されるようなものであるAssemblyB
のIL。これは、明日I_CONST_VALUE
、将来20に更新することを意味します。AssemblyB
私がそれを再コンパイルするまで、まだ2があります。readonly
値は、似ているref
メモリロケーションへ。値はAssemblyB
のILには組み込まれません。これは、メモリの場所が更新された場合、AssemblyB
再コンパイルせずに新しい値を取得することを意味します。したがって、I_RO_VALUE
が30に更新された場合は、ビルドするだけで済みますAssemblyA
。すべてのクライアントを再コンパイルする必要はありません。したがって、定数の値が変化しないことが確実な場合は、を使用してくださいconst
。
public const int CM_IN_A_METER = 100;
ただし、変更される可能性のある定数がある場合(たとえば、精度が正確である場合)、または不明な場合は、readonly
。
public readonly float PI = 3.14;
更新:阿久は彼が最初にこれを指摘した言及を得る必要があります。また、これを学んだ場所に接続する必要があります。効果的なC#-Bill Wagner
static
-ポイントは、最も重要かつ有用なポイントのようですconsts are implicitly static
readonly
変数はコンストラクタの外で変更できます(リフレクション)。コンストラクタの外で変数を変更できないようにするのはコンパイラだけです。
readonly
変数は、リフレクションを介しても、コンストラクターが終了すると変更できません。ランタイムはたまたまこれを強制しません。ランタイムはまた、あなたが変更しないことを強制しないように起こるstring.Empty
の"Hello, world!"
が、私はまだこれが行うことを主張していないだろうstring.Empty
修正、またはそのコードは、それが想定するべきではありませんstring.Empty
常に長さゼロの文字列になります。
constsには落とし穴があります!別のアセンブリから定数を参照すると、その値は呼び出し元のアセンブリに直接コンパイルされます。このようにして、参照されているアセンブリの定数を更新しても、呼び出し元のアセンブリでは変更されません。
追加するだけで、参照タイプの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
}
}
string
定数として使用できるもの以外に参照タイプはありますか?
const
文字列以外の参照型を使用できますが、定数は値のみを持つことができますnull
。
これはそれを説明します。概要:constは宣言時に初期化する必要があります。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
キーワードを使用してフィールドとして宣言され、宣言されたとおりに初期化する必要があります。
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;
}
}
const
static
(暗黙的に静的です)。読み取り専用
static const int i = 0;
const
メソッド内で宣言ができない理由を説明できますか?
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);
私たちのオフィスのチームメンバーの1人が、const、static、およびreadonlyをいつ使用するかについて次のガイダンスを提供しました。
最後に、constフィールドは静的ですが、その逆は当てはまりません。
どちらも定数ですが、コンパイル時にconstも使用できます。これは、違いの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; }
}
}
いつ使用するconst
かreadonly
const
readonly
App.config
(ただし、一度初期化すると変更できません)constとマークされた変数は、厳密に型指定された#defineマクロに過ぎず、コンパイル時にconst変数参照はインラインリテラル値に置き換えられます。結果として、この方法で使用できるのは、特定の組み込みプリミティブ値タイプのみです。readonlyとマークされた変数は、コンストラクターで実行時に設定でき、それらの読み取り専用性は実行時にも強制されます。これに関連するいくつかの小さなパフォーマンスコストがありますが、これは、任意のタイプ(参照タイプも含む)で読み取り専用を使用できることを意味します。
また、const変数は本質的に静的ですが、読み取り専用変数は必要に応じてインスタンス固有にすることができます。
別の落とし穴。
constは実際には基本的なデータ型でのみ機能するため、クラスを操作したい場合は、ReadOnlyを使用するよう「強制」されていると感じるかもしれません。ただし、トラップには注意してください。ReadOnlyは、オブジェクトを別のオブジェクトに置き換えることができないことを意味します(別のオブジェクトを参照させることはできません)。しかし、オブジェクトへの参照を持つすべてのプロセスは、内部の値を自由に変更できますのます。
したがって、ReadOnlyはユーザーが変更できないことを意味するものと誤解しないでください。C#には、クラスのインスタンス化によって内部値が変更されるのを防ぐ単純な構文はありません(私の知る限り)。
C#.Netのconstフィールドとreadonlyフィールドには顕著な違いがあります
constはデフォルトでは静的であり、後で変更できない定数値で初期化する必要があります。コンストラクタでも値の変更は許可されていません。すべてのデータ型で使用できるわけではありません。exDateTimeの場合。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は静的として宣言できますが、必須ではありません。宣言時に初期化する必要はありません。その値は、コンストラクターを使用して割り当てまたは変更できます。そのため、インスタンスクラスメンバーとして使用すると利点があります。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を使用すると不可能です。
定数はリテラル値としてコンシューマーにコンパイルされますが、静的文字列は定義された値への参照として機能します。
演習として、外部ライブラリを作成してコンソールアプリケーションで使用し、ライブラリの値を変更して再コンパイルし(コンシューマプログラムを再コンパイルせずに)、DLLをディレクトリにドロップしてEXEを手動で実行してください。定数文字列は変更されません。
絶え間ない
constフィールドが定義されている場合、値を提供する必要があります。次に、コンパイラは定数の値をアセンブリのメタデータに保存します。つまり、定数はboolean、char、byteなどのプリミティブ型に対してのみ定義できます。定数は常にインスタンスメンバーではなく、静的メンバーと見なされます。
読み取り専用
読み取り専用フィールドは、実行時にのみ解決できます。つまり、フィールドが宣言されている型のコンストラクターを使用して、値の値を定義できます。検証は、読み取り専用フィールドがコンストラクター以外のメソッドによって書き込まれないことをコンパイラーが行います。
この記事で説明されている両方の詳細
constとreadonlyは似ていますが、完全に同じではありません。constフィールドはコンパイル時の定数です。つまり、その値はコンパイル時に計算できます。読み取り専用フィールドを使用すると、型の構築中に一部のコードを実行する必要がある追加のシナリオが可能になります。作成後、読み取り専用フィールドは変更できません。
たとえば、constメンバーを使用して、次のようなメンバーを定義できます。
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
3.14や0などの値はコンパイル時の定数だからです。ただし、タイプを定義し、そのプレハブインスタンスをいくつか提供する場合を考えてみます。たとえば、Colorクラスを定義して、Black、Whiteなどの一般的な色に「定数」を提供したい場合があります。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のクライアントがそれをいじるのを防ぐ方法はありません。言うまでもなく、これは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メンバーは常に静的ですが、読み取り専用メンバーは通常のフィールドと同様に静的でもそうでなくてもかまいません。
これら2つの目的で単一のキーワードを使用することは可能ですが、これによりバージョン管理の問題またはパフォーマンスの問題が発生します。この(const)に単一のキーワードを使用して、開発者が書いたと仮定します。
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フィールドの値はコンパイル時定数に設定されます。
要確認:参照タイプの場合、両方の場合(静的およびインスタンス)、readonly修飾子は、フィールドへの新しい参照の割り当てを防止するだけです。具体的には、参照によってポイントされるオブジェクトを不変にしません。
詳細については、このトピックに関するC#のよく寄せられる質問を参照してください:http : //blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx
人々が上で言ったことに追加するための一つ。読み取り専用の値を含むアセンブリがある場合(たとえば、readonly MaxFooCount = 4;)、そのアセンブリの新しいバージョンを別の値で出荷することで(たとえば、readonly MaxFooCount = 5;)、呼び出し側のアセンブリが表示する値を変更できます。
しかし、constを使用すると、呼び出し元がコンパイルされたときに呼び出し元のコードに組み込まれます。
このレベルのC#の熟練度に達している場合は、Bill Wagnerの著書「Effective C#:50 Specific Ways to Improve C#」でこの質問に詳細に答える(そしてその他49のこと)の準備ができています。