webdevqa.jp.net

Const配列を宣言する

次のようなものを書くことは可能ですか?

public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
388
Jaime Oro

はい、でもreadonlyではなくconstと宣言する必要があります。

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

その理由は、constはコンパイル時に値がわかっているフィールドにしか適用できないからです。ここに示した配列初期化子はC#では定数式ではないため、コンパイラエラーが発生します。

宣言するとreadonlyはその問題を解決します。実行時まで値が初期化されないからです(ただし、配列が最初に使用される前に初期化されることが保証されています)。

最終的に達成したいことによっては、enumを宣言することを検討することもできます。

public enum Titles { German, Spanish, Corrects, Wrongs };
591
Cody Gray

配列をreadonlyとして宣言できますが、readonly配列の要素を変更できることに注意してください。

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

Codyが提案しているようにenum、またはIListを使用することを検討してください。

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
51
Branimir

配列はオブジェクトであり、実行時にのみ作成でき、constエンティティはコンパイル時に解決されるため、 'const'配列を作成することはできません。

代わりにできることは、配列を "readonly"として宣言することです。実行時に値を設定できることを除けば、constと同じ効果があります。それは一度だけ設定することができ、その後それは読み取り専用(すなわちconst)値である。

41
JAiro

C#6以降、次のように書くことができます。

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

C#:C#6.0の新機能と改善された機能 (特に「式本体の関数とプロパティ」の章)

これにより読み取り専用の静的プロパティが作成されますが、返される配列の内容を変更することはできますが、このプロパティを再度呼び出すと、元の変更されていない配列が再び取得されます。

わかりやすくするために、このコードは次のものと同じです(または実際にはその省略形です)。

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

このアプローチには欠点があることに注意してください。実際には、それぞれの参照ごとに新しい配列がインスタンス化されるため、非常に大きな配列を使用している場合、これは最も効率的な解決策にはなりません。しかし、あなたが同じ配列を再利用するなら(例えばそれをプライベート属性に入れることによって)、それは再び配列の内容を変更する可能性を開くでしょう。

不変の配列(またはリスト)を使いたい場合は、次のものも使用できます。

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

しかし、文字列[]にキャストし直して内容を変更することができるため、これは変更のリスクがあります。

((string[]) Titles)[1] = "French";
8
mjepson

別の方法をとることもできます。配列を表す定数文字列を定義し、必要に応じて文字列を配列に分割します。

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

この方法では、構成に格納し、必要に応じて配列に変換できる定数が得られます。

アラステア

6
Alastair

IReadOnlyListインターフェイスの背後で配列を宣言すると、実行時に宣言された定数値を持つ定数配列が得られます。

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

.NET 4.5以降で利用可能です。

5
Richard Garside

tdbeckett's answer を改善する.NET Framework v4.5 +ソリューション

using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);

注:コレクションが概念的に一定であることを考えると、classレベルで宣言するためにstaticにすることは理にかなっています。

上記:

  • プロパティの暗黙的なバッキングフィールドを初期化しますonce配列を使用します。

    • { get; }-つまり、プロパティのみを宣言するgetter-は、プロパティ自体を暗黙的に読み取り専用にするものであることに注意してください(readonly{ get; }を組み合わせようとすると、実際には構文エラーになります)。

    • または、{ get; }を省略してreadonlyを追加し、質問のようにプロパティの代わりにフィールドを作成することもできますが、publicデータメンバーをフィールドではなくプロパティとして公開するのが適切です形成する習慣。

  • array-like structureインデックス付きアクセスを許可)を作成します。これはtrulyおよび堅牢に読み取り専用です。(概念的には1回、作成)、両方に関して:

    • コレクションの変更の防止全体として(要素の削除や追加、変数への新しいコレクションの割り当てなど)。
    • 個々の要素の変更の防止
      (偶数間接変更は不可能です-IReadOnlyList<T>ソリューションとは異なり、a (string[])キャストを使用して、 mjepsenの有用な回答 に示すように、elements
      同じ脆弱性は、IReadOnlyCollection<T>インターフェイスにも適用されます。これは、名前がクラスに類似しているにも関わらずReadOnlyCollectionindexed accessもサポートしていないため、配列のようなアクセスを提供するには基本的に不適切です。)
5
mklement0

私のニーズに合わせて、不可能なstaticではなくconst配列を定義していますが、うまくいきます:public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

5
ALZ

これはあなたが望むことをする方法です:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

読み取り専用の配列を作成するのとよく似ています。

3
tdbeckett

私はあなたがそれをただ読み取り専用にすることができると信じます。

2
skaz

完全を期すために、今はImmutableArrayも自由に使用できます。これは本当に不変であるべきです:

public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

System.Collections.Immutable NuGetリファレンスが必要です

https://msdn.Microsoft.com/ja-jp/library/mt452182(v=vs.111).aspx

1
shurik

配列はおそらく実行時にしか評価できないものの1つです。定数はコンパイル時に評価されなければなりません。 "const"の代わりに "readonly"を使ってみてください。

1
nemke

別の方法として、読み取り専用配列で要素を変更できるという問題を回避するには、代わりに静的プロパティを使用できます。 (個々の要素はまだ変更可能ですが、これらの変更は配列のローカルコピーに対してのみ行われます。)

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

もちろん、毎回新しい文字列配列が作成されるので、これは特に効率的ではありません。

0
Hutch