2

アプリケーションの存続期間中に変更されない辞書オブジェクトがいくつかあります。私は静的読み取り専用変数を使用することを計画しています、誰かが以下の点で入力を提供できますか?

  1. 静的読み取り専用プロパティとして直接初期化することと、プライベート読み取り専用静的変数でバックアップされたGET演算子を使用して静的プロパティを初期化することの違い。

  2. パブリック静的変数を使用しないようにオンラインで読んだので、それらを使用するリスクはありますか?これはこの状況に当てはまりますか?

4

4 に答える 4

3

アプリケーションの存続期間中に変更されない辞書オブジェクトがいくつかあります。

Dictionary 型の変数をマークするとreadonly、割り当てた辞書が別の辞書に置き換えられなくなります。そのディクショナリを読み取り専用にしないでください。つまり、発信者がそのディクショナリを手に入れるとすぐに、任意の方法で自由に変更したり、きれいに消去したり、誤った値を設定したり (誤って、間違いない)。Dictionary を読み取り専用にする必要がある場合は、この回答から読み取り専用ラッパーの実装を借用することを検討してください。

一般に、変数の上にプロパティを追加する、または{get;private set;}自動プロパティを持つことの唯一の利点はreadonly static、setter で追加のチェックを実行できること、または getter にコードを追加できることです (たとえば、アクセス統計を収集したり、ロギング用)。リフレクションを介してフィールドにアクセスすることにも影響があります。あなたがそのようなことをしているようには見えないので、読み取り専用変数を公開することは適切に聞こえ、追加のリスクはありません。

編集: (リフレクションの使用について) リフレクションを介してオブジェクト データにアクセスする場合は、プロパティXyzまたはフィールドにアクセスしているかどうかを指定する必要がありますXyz。対照的に、C# プログラムを作成する場合は、 を記述SomeClass.Xyzします。コンパイラは、それがプロパティかフィールドかを判断します。field を公開するクラスを作成し、Xyz後でそれを property に置き換えることにした場合、直接Xyz参照するコードを再コンパイルするだけで済みます。ただし、リフレクション API を介してアクセスするコードを作成した場合は、コンパイラが変更をキャッチできないため、そのコードを書き直す必要があります。Xyz Xyz

于 2013-02-14T22:15:58.033 に答える
1

フィールドとして、静的コンストラクターの実行後に変更することはできないため、静的読み取り専用プロパティでラップすることに不変性とスレッドセーフの観点から理由はありません。

ただし、フィールドのプロパティが必要になる場合があることに注意してください。データバインディングは、リフレクションの使用と同様に1つの例です(どちらか一方を標準化すると簡単になる場合があります)。

于 2013-02-14T22:07:41.840 に答える
1

public static readonly フィールドと public static プロパティの間にはほとんど違いはありません。このプロパティはアクセスをある程度保護しますが、値を返すだけであれば、この 2 つに大きな違いはありません。

// access between these two is almost identical
public class Foo
{
    public readonly static IDictionary<string, int> bar =
        new Dictionary<string, int>();
    public static IDictionary<string, int> Bar
    {
         get { return bar; }
    }
}

あなたが遭遇しようとしている問題は、フィールドreadonlyがまだ可変であるとマークされているにもかかわらずです。これFoo.Bar.Clear(); を解決するには、コピーを作成してそれを返すか、読み取り専用の辞書実装を使用することができます。

public class Foo
{
    private readonly static IDictionary<string, int> bar =
        new Dictionary<string, int>();
    public static IDictionary<string, int> Bar
    {
        // now any calls like Foo.Bar.Clear(); will not clear Foo.bar
        get { return new Dictionary<string, int>(bar); }
    }
}

次に、アイテムを追加または削除する必要がFoo.Barある場合は、基になるオブジェクトの変更方法を制限する関数を作成できます。

public static void AddItem(string key, int value)
{ }
public static void RemoveItem(string key)
{ }

ReadonlyDictionary実装を使用する場合でも、ディクショナリのTKeyまたはTValueが可変である場合、変更で問題が発生する可能性があります。

全体として、public static 変数を避ける理由はここでも当てはまります。使用するコードが再利用されるたびにドラッグされる静的な依存関係を導入していますFoo.Bar。静的にアクセスしているオブジェクトが不変かつ読み取り専用でない限り、予期しない副作用がいくつも発生する可能性があります。

コンポジションルートでオブジェクトの単一インスタンスを作成し、それを依存関係が必要なオブジェクトに渡す方がよいでしょう。

public void CompRoot()
{
     var bar = new ReadonlyDictionary(
         ... initialize with desired values ...
          // also this object is not in .NET but there
          // are many available on the net
     );

     var obj = new UsesBarDependency(bar);
}

public class UsesBarDependency
{
     private readonly ReadonlyDictionary bar;

     public UsesBarDependency(ReadonlyDictionary bar)
     {
          if (bar == null)
              throw new ArgumentNullException("bar");
          this.bar = bar;
     }

     public void Func()
     {
         // use to access the dependency
         this.bar 
         // over
         Foo.Bar
     }
 }

そうすることで、ユーザーは、静的依存関係の使用を強制されるのではなく、オブジェクトにUsesBarDependency何でも提供できます。ReadonlyDictionaryFoo.Bar

于 2013-02-14T22:39:18.403 に答える
1

できるだけプロパティを使用することをお勧めします。実際のパフォーマンスの低下はありません。これが、パブリック フィールドを持つ理由として最も頻繁に述べられている理由です。主な利点は、将来の実装の詳細の変更から身を守ることです。フィールドを使用すると、コンパイルされた呼び出し元は毎回フィールドへのアクセスに関連付けられます。

于 2013-02-14T22:13:48.583 に答える