質問

違いは何ですか const そして readonly 一方を他方よりも使用しますか?

役に立ちましたか?

解決

見た目の違いとは別に、

  • の定義時に値を宣言する必要がある 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 値、これは検索と置換のようなもので、値 2 が AssemblyBのイルです。つまり、明日更新するなら I_CONST_VALUE 将来的には20まで。 AssemblyB 再コンパイルするまでは 2 が残ります.
  • の場合 readonly 値、それは次のようなものです ref 記憶の場所へ。値は焼き付けられていません AssemblyBのイルです。これは、メモリの場所が更新されると、 AssemblyB 再コンパイルせずに新しい値を取得します。それで、もし I_RO_VALUE 30 に更新されている場合は、ビルドするだけで済みます AssemblyA. 。すべてのクライアントを再コンパイルする必要はありません。

したがって、定数の値が変わらないと確信できる場合は、 const.

public const int CM_IN_A_METER = 100;

ただし、変更される可能性のある定数がある場合 (例:に関して。精度)..または、疑わしい場合は、 readonly.

public readonly float PI = 3.14;

アップデート:アクは最初にこのことを指摘したので言及してもらう必要がある。また、これをどこで学んだのかをプラグインする必要があります。 効果的な C# - ビル・ワグナー

他のヒント

const には注意点があります。別のアセンブリから定数を参照すると、その値は呼び出したアセンブリに直接コンパイルされます。そうすれば、参照先アセンブリの定数を更新しても、呼び出し元アセンブリでは定数が変更されなくなります。

定数

  • 定数はデフォルトでは静的です
  • コンパイル時に値が必要です (たとえば、3.14 * 2 ただし、メソッドを呼び出すことはできません)
  • 関数内で宣言できる
  • それらを使用するすべてのアセンブリにコピーされます (すべてのアセンブリは値のローカル コピーを取得します)
  • 属性で使用可能

読み取り専用インスタンスフィールド

  • コンストラクターが終了するまでに値が設定されている必要があります
  • インスタンスの作成時に評価されます

静的な読み取り専用フィールド

  • コードの実行がクラス参照に到達したとき (新しいインスタンスが作成されたとき、または静的メソッドが実行されたとき) に評価されます。
  • 静的コンストラクターが完了するまでに評価値が必要です
  • これらに ThreadStaticAttribute を設定することはお勧めできません (静的コンストラクターは 1 つのスレッドでのみ実行され、そのスレッドの値を設定します。他のすべてのスレッドではこの値が初期化されません)

付け加えておきますが、参照型の 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 はコンストラクターで初期化できます (したがって、使用されるコンストラクターに応じて異なる値になります)。

編集:微妙な違いについては、上記の Gishu の注意点を参照してください。

const:どこにも変更できません。

readonly:この値はコンストラクター内でのみ変更できます。通常の機能では変更できません。

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 member は、不変の値を表すという点で定数と似ています。違いは、 readonly メンバーは実行時にコンストラクター内で初期化できるほか、宣言時に初期化することもできます。

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

定数

  • として宣言することはできません static (それらは暗黙的に静的です)
  • 定数の値はコンパイル時に評価されます
  • 定数は宣言時にのみ初期化されます

読み取り専用

  • インスタンスレベルまたは静的なものにすることができます。
  • 値は実行時に評価されます
  • readonly は、宣言またはコンストラクター内のコードによって初期化できます。

const はコンパイル時の定数ですが、readonly では実行時に値を計算し、コンストラクターまたはフィールド初期化子に設定できます。したがって、「const」は常に定数ですが、「readonly」は割り当てられると読み取り専用になります。

エリック・リッパート C# チームのメンバーは、さまざまな種類の不変性に関する詳細情報を持っています

ここに別のリンクがあります const がバージョンセーフではない、または参照型に関連していないことを示しています。

まとめ:

  • const プロパティの値はコンパイル時に設定され、実行時に変更することはできません
  • Const を静的としてマークすることはできません。読み取り専用フィールドとは異なり、キーワードは静的であることを示します。
  • Const には値 (プリミティブ) 型以外を指定できません
  • readonly キーワードは、フィールドを変更不可としてマークします。ただし、プロパティはクラスのコンストラクター内で変更できます。
  • readonly Only キーワードを static と組み合わせて、(少なくとも表面上は) const と同じように動作させることもできます。両者のILを見ると顕著な違いがあります
  • const フィールドは、IL では「リテラル」としてマークされますが、readonly は「initonly」です。

読み取り専用 :値は実行時に Ctor を通じて変更できます。ただし、メンバー関数を介したものではありません

絶え間ない :デフォルトの静的による。値はどこからも変更できません (Ctor、関数、ランタイムなど、どこからも変更できません)

さらにもう一つの落とし穴:読み取り専用の値は、リフレクションを介して「不正な」コードによって変更される可能性があります。

var fi = this.GetType()
             .BaseType
             .GetField("_someField", 
                       BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);

リフレクションを使用して C# のプライベート読み取り専用継承フィールドを変更できますか?

私は信じます const value はすべてのオブジェクトで同じです (そしてリテラル式で初期化する必要があります)。 readonly インスタンス化ごとに異なる場合があります...

私たちのオフィスのチーム メンバーの 1 人が、const、static、readonly をいつ使用するかについて次のようなガイダンスを提供しました。

  • 使用 定数 実行時にわかる型 (文字列リテラル、int、double、列挙型など) の変数がある場合、クラスのすべてのインスタンスまたはコンシューマーが、値が変更されない場所にアクセスできるようにする必要があります。
  • 使用 静的 値が変更される可能性のあるデータに、クラスのすべてのインスタンスまたはコンシューマがアクセスできるようにしたい場合。
  • 使用 静的読み取り専用 実行時に知ることができない型の変数 (オブジェクト) があり、クラスのすべてのインスタンスまたはコンシューマーが値が変更されない場所にアクセスできるようにしたい場合。
  • 使用 読み取り専用 インスタンス レベルの変数がある場合、オブジェクトの作成時に変更すべきではないことがわかります。

最後に 1 つ注意してください: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 とマークされた変数は、厳密に型指定された #define マクロにすぎず、コンパイル時に const 変数参照はインライン リテラル値に置き換えられます。結果として、この方法で使用できるのは、特定の組み込みプリミティブ値タイプのみです。読み取り専用とマークされた変数は、実行時にコンストラクターで設定でき、実行時にも読み取り専用が強制されます。これに関連して若干のパフォーマンス コストが発生しますが、任意の型 (参照型も含む) で読み取り専用を使用できることを意味します。

また、const 変数は本質的に静的ですが、readonly 変数は必要に応じてインスタンス固有にすることができます。

別の 落とし穴.

const は実際には基本的なデータ型でしか機能しないため、クラスを操作したい場合は ReadOnly を使用することが「強制」されているように感じるかもしれません。ただし、罠には気をつけてください!ReadOnly は、オブジェクトを別のオブジェクトに置き換えることができない (別のオブジェクトを参照させることができない) ことを意味します。ただし、オブジェクトへの参照を持つプロセスは値を自由に変更できます。 内部 オブジェクト!

したがって、ReadOnly がユーザーが変更できないことを意味していると混同しないでください。(私の知る限り) C# には、クラスのインスタンス化によって内部値が変更されることを防ぐ簡単な構文はありません。

C#.Net の const フィールドと readonly フィールドには大きな違いがあります

const はデフォルトでは静的であり、定数値で初期化する必要があります。後で変更することはできません。コンストラクター内でも値の変更は許可されません。すべてのデータ型で使用できるわけではありません。元の 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 の読み取り専用フィールドの値は 5 になり、objTwo の値は 10 になります。const を使用するとそれは不可能です。

定数はリテラル値としてコンシューマにコンパイルされ、静的文字列は定義された値への参照として機能します。

演習として、外部ライブラリを作成してコンソール アプリケーションで使用してから、ライブラリ内の値を変更して再コンパイルし (コンシューマ プログラムを再コンパイルせずに)、DLL をディレクトリにドロップして EXE を手動で実行してみてください。定数文字列が変更されないことを確認します。

絶え間ない

const フィールドが定義されている場合は、その値を const フィールドに指定する必要があります。次に、コンパイラは定数の値をアセンブリのメタデータに保存します。これは、定数は boolean、char、byte などのプリミティブ型に対してのみ定義できることを意味します。定数は、インスタンス メンバーではなく、常に静的メンバーとみなされます。

読み取り専用

読み取り専用フィールドは実行時にのみ解決できます。つまり、フィールドが宣言されている型のコンストラクターを使用して、値の値を定義できるということです。検証は、読み取り専用フィールドがコンストラクター以外のメソッドによって書き込まれていないことをコンパイラーによって行われます。

両方についてさらに詳しく この記事で説明されています

定数

  1. const キーワードはフィールドまたはローカル変数に適用できます
  2. 宣言時に const フィールドを割り当てる必要があります
  3. コンパイル後に const 値が IL コード自体に埋め込まれるため、メモリが割り当てられません。これは、const 変数の出現をすべて検索し、その値で置換するようなものです。したがって、コンパイル後の IL コードには、const 変数の代わりにハードコーディングされた値が含まれます。
  4. C# の Const はデフォルトでは静的です。
  5. 値はすべてのオブジェクトに対して一定です
  6. DLL のバージョン管理の問題があります。これは、パブリック const 変数またはプロパティを変更するたびに (実際、理論的には変更されるべきではありません)、この変数を使用する他の DLL またはアセンブリを再構築する必要があることを意味します。
  7. 定数として宣言できるのは C# 組み込み型のみです
  8. Const フィールドを ref または out パラメータとして渡すことはできません

読み取り専用

  1. readonly キーワードはフィールドにのみ適用され、ローカル変数には適用されません
  2. 読み取り専用フィールドは宣言時またはコンストラクターで割り当てることができますが、他のメソッドでは割り当てることができません。
  3. 読み取り専用フィールドに動的メモリが割り当てられ、実行時に値を取得できます。
  4. Readonly は、クラスのインスタンスのみを介してアクセスされるように作成されたオブジェクトに属します。クラスメンバーにするには、readonly の前に static キーワードを追加する必要があります。
  5. 値は使用されるコンストラクターに応じて異なる場合があります(クラスのオブジェクトに属するため)。
  6. 非プリミティブ型 (参照型) を読み取り専用として宣言した場合、参照はそれに含まれるオブジェクトではなく不変になります。
  7. 値は実行時に取得されるため、読み取り専用のフィールド/プロパティに関する DLL のバージョン管理の問題はありません。
  8. readonly フィールドをコンストラクター コンテキストの ref または out パラメーターとして渡すことができます。

主に;静的な読み取り専用フィールドの値は実行時に非定数値に割り当てることができますが、const には定数値を割り当てる必要があります。

const である必要があります ハードコードされた, 、 一方 readonly できる コンストラクターで設定する クラスの。

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) を使用し、開発者が次のように書いたと仮定します。

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 の開発者はインテントを指定できます。これにより、バージョン管理の動作が向上し、パフォーマンスも向上します。

ReadOnly : 値はクラスのコンストラクターから 1 回だけ初期化されます。
定数:どの関数でも初期化できますが、1 回だけ初期化できます

違いは、静的な読み取り専用フィールドの値が実行時に設定されるため、プログラムの実行ごとに異なる値を持つことができることです。ただし、const フィールドの値はコンパイル時定数に設定されます。

覚えて:参照型の場合、両方の場合 (静的とインスタンス)、readonly 修飾子はフィールドへの新しい参照の割り当てを禁止するだけです。特に、参照が指すオブジェクトを不変にするわけではありません。

詳細については、このトピックに関する C# のよくある質問を参照してください。http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx

定数変数はコンパイル時に宣言され、初期化されます。ワードの後で値を変更することはできません。読み取り専用変数は、クラスの静的コンストラクターからのみ初期化されます。読み取り専用は、実行時に値を割り当てる場合にのみ使用されます。

上で人々が言っ​​たことに付け加えたいことが 1 つあります。読み取り専用の値を含むアセンブリがある場合 (例:読み取り専用 MaxFooCount = 4;)、異なる値(例:読み取り専用 MaxFooCount = 5;)

ただし、const を使用すると、呼び出し元がコンパイルされるときに呼び出し元のコードに組み込まれます。

C# の熟練度がこのレベルに達している場合は、Bill Wagner の書籍『Effective C#』を読む準備ができています。この質問に詳細に答える(およびその他49)、C#を改善する50の具体的な方法。

主な違いは、Const が C での #DEFINE に相当することです。この番号は文字通りプリコンパイラのように置き換えられます。Readonly は実際には変数として扱われます。

この区別は、プロジェクト B のパブリック定数に依存するプロジェクト A がある場合に特に関係します。パブリック定数が変更されたとします。const/readonly の選択は、プロジェクト A の動作に影響を与えます。

定数:プロジェクト A は、定数を代入してコンパイルされているため、新しい値を取得できません (もちろん、新しい const で再コンパイルしない限り)。

読み取り専用:プロジェクト A は常にプロジェクト B に変数値を要求するため、プロジェクト B のパブリック定数の新しい値を取得します。

正直に言うと、真に汎用的な定数を除くほぼすべての場合に readonly を使用することをお勧めします (例:円周率、インチからセンチメートルまで)。変更される可能性があるものについては、読み取り専用を使用することをお勧めします。

これが役立つことを願っています、アラン。

簡単に言うと、Const はコンパイル時、readonly は実行時です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top