web-dev-qa-db-ja.com

静的読み取り専用とconst

conststatic readonlyフィールドについて読みました。定数値のみを含むクラスがいくつかあります。システム内のさまざまなものに使用されます。それで、私の観察が正しいかどうか疑問に思います:

この種の定数値は、公開されているすべてのものに対して常にstatic readonlyであるべきですか?そして、内部/保護/非公開の値にのみconstを使用しますか?

おすすめは何ですか? static readonlyフィールドを使わなくても、むしろプロパティを使うべきです。

1300
Svish

public static readonlyフィールドは少し変わっています。 public staticプロパティ(getname__のみ)はより一般的になります(おそらくprivate static readonlyフィールドに裏付けられています)。

constname__の値はコールサイトに直接書き込まれます。これは両刃です。

  • おそらくconfigから、実行時に値を取得しても意味がありません。
  • constの値を変更した場合は、すべてのクライアントを再構築する必要があります。
  • しかし、それはメソッド呼び出しを避けているので、速くすることができます...
  • ...とにかくJITによってインライン化されている可能性があります

値が 決して 変更されない場合、constは問題ありません - Zeroname__などは妥当なconstを作成します; pそれ以外は、staticname__プロパティがより一般的です。

893
Marc Gravell

Consumer が別のアセンブリにある場合は、static readonlyを使用します。 2つの異なるアセンブリにconst Consumer を含めることは、 自分で足を撃つための素晴らしい方法です

224
Michael Stum

注目すべき関連性の高いものはほとんどありません。

const int a

  • 初期化する必要があります。
  • 初期化は コンパイル時 にする必要があります。

readonly int a

  • 初期化せずにデフォルト値を使用できます。
  • 初期化は 実行時 で行うことができます(編集:コンストラクタ内のみ)。
191
Peter

これは他の答えを補足するものです。私はそれらを繰り返さないでしょう(今4年後)。

constname__と非constのセマンティクスが異なる場合があります。例えば:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

Truename__を出力します。

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

Falsename__を書き込みます。

その理由は、メソッド x.Equals には2つのオーバーロードがあり、1つはshortname__(System.Int16)を受け取り、もう1つはobjectname__(System.Object)を受け取ります。今度の問題は、どちらか一方または両方が私のyname__引数に適用されるかどうかです。

yname__がコンパイル時定数(リテラル)の場合、constname__の場合、intname__が定数であれば、暗黙の変換fromshorttointname__が存在することが重要になります。 C#コンパイラは、その値がshortname__の範囲内にあることを検証します(これは42です)。 C#言語仕様の 暗黙の定数式変換 を参照してください。そのため、両方の過負荷を考慮する必要があります。オーバーロードEquals(short)が優先されます(任意のshortname__はobjectname__ですが、すべてのobjectname__がshortname__であるわけではありません)。そのためyname__はshortname__に変換され、そのオーバーロードが使用されます。 Equalsname__は、同じ値を持つ2つのshortname__を比較し、それによってtruename__が得られます。

yname__が定数ではない場合、intname__からshortname__への暗黙的変換は存在しません。これは、一般的にintname__がshortname__に収まるには大きすぎる可能性があるためです。 (explicit変換は存在しますが、私はEquals((short)y)とは言わなかったので、関係ありません。)オーバーロードが1つだけ適用されることがわかります、Equals(object)。そのためyname__はobjectname__に囲まれています。 Equalsname__はSystem.Int16System.Int32を比較しようとしています、そして実行時型が一致しないので、それはfalsename__をもたらすでしょう。

稀なケースでは、constname__型のメンバーをstatic readonlyフィールドに変更すると(またはそれが可能な場合は別の方法でも)、プログラムの動作が変わる可能性があると結論します。

162

注意すべき点は、 const はプリミティブ型/値型に制限されていることです(例外は文字列です)。

87
Chris S

readonlyキーワードはconstキーワードとは異なります。 constフィールドはフィールドの宣言時にのみ初期化できます。 readonlyフィールドは宣言時またはコンストラクタ内で初期化できます。したがって、readonlyフィールドは、使用されるコンストラクタに応じて異なる値を取ります。また、constフィールドはコンパイル時定数ですが、readonlyフィールドは実行時定数に使用できます

ここに短くて明確なMSDNリファレンス

24
yazanpro

静的読み取り専用 :値は実行時にstaticコンストラクタを介して変更できます。しかし、メンバー機能を通してではありません。

定数 :デフォルトではstaticです。値はどこからも変更できません(Ctor、Function、runtimeなどno-where)。

読み取り専用 :値は実行時にコンストラクタを介して変更できます。しかし、メンバー機能を通してではありません。

あなたは私のレポを見てみることができます: C#のプロパティの種類

21

constreadonlyは似ていますが、まったく同じではありません。

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

15

私が好むのは、可能な限り const を使用することです。上記のように、これはリテラル式または評価を必要としないものに限定されます。

私がその制限に立ち向かうならば、1つ注意を払って static readonly にフォールバックする。 Marcが here に言及しているように、私は一般的にgetterとbacking private static readonly フィールドでpublic staticプロパティを使用します。

12
Peter Meyer

Const: Constは "constant"に他なりません。その値はコンパイル時には定数です。そしてそれに値を割り当てることは必須です。デフォルトではconstは静的であり、プログラム全体を通してconst変数の値を変更することはできません。

静的読み取り専用: 静的読み取り専用型変数の値は、実行時に割り当てることも、コンパイル時に割り当てて実行時に変更することもできます。しかし、この変数の値は静的コンストラクタでしか変更できません。それ以上変更することはできません。実行時に一度だけ変更できます

参照: c-sharpcorner

7
mayank

静的読み取り専用フィールドは、後のバージョンで変更される可能性がある値を他のアセンブリに公開する場合に有利です。

たとえば、アセンブリXが次のように定数を公開するとします。

public const decimal ProgramVersion = 2.3;

Assembly YXを参照してこの定数を使用する場合、コンパイル時に値2.3がAssembly Yに焼き付けられます。これは、Xが後で2.4に設定された定数で再コンパイルされた場合でも、Yが再コンパイルされるまで、Yは以前の2.3の値を使用します。静的な読み取り専用フィールドはこの問題を回避します。

もう1つの見方は、将来変更される可能性のある値は定義上一定ではないため、1つとして表すべきではないということです。

6
Yagnesh Cangi

const:

  1. 宣言時に値を指定する必要があります
  2. 時定数をコンパイルする

読み取り専用:

  1. 値は宣言時または実行時にコンストラクタを使用して指定できます。値は使用するコンストラクタによって異なります。
  2. 実行時定数
3
dasumohan89

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では不可能です。

2
Chirag

Const :const変数値は宣言と一緒に定義する必要があり、その後は変更されません。constは暗黙的に静的なので、クラスインスタンスを作成しなくてもアクセスできます。 これはコンパイル時に値を持ちます

ReadOnly :宣言時および実行時のコンストラクタの使用時に定義できる読み取り専用の変数値。読み取り専用変数はクラスインスタンスなしでアクセスできません。

静的読み取り専用 :宣言中に静的読み取り専用変数値を定義することはできますが、他のコンストラクターを使用して定義することはできません。

私たちが異なるアセンブリで変数を消費しなければならないならば、静的なreadonlyはより良い選択になるでしょう。下のリンクで完全な詳細をチェックしてください

https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/ /

1
user1756922

定数は名前が暗示するようなもので、変化しないフィールドで、通常はコンパイル時にコード内で静的に定義されます。

読み取り専用変数は、特定の条件下で変更される可能性があるフィールドです。

最初に定数のように宣言したときに初期化することもできますが、通常はコンストラクタ内でのオブジェクト構築中に初期化されます。

上記の条件では、初期化が行われた後に変更することはできません。

静的な読み取り専用は、私にとっては不適切な選択のように思えます。静的な場合は変更されないので、public constを使用します。単独または通常の変数です。

また、もう1つの重要な違いは、定数はクラスに属し、読み取り専用変数はインスタンスに属するということです。

0