4

コード分​​析エラーを順守する過程で、プロパティをプライベート セッターを持つように変更しています。それから、その理由をもう少し理解しようとしました。いくつかの調査から、MS は次のように述べています

書き込み可能なコレクション プロパティを使用すると、ユーザーはコレクションをまったく別のコレクションに置き換えることができます。

そして、答えはここにあり、次のように述べています。

オブジェクトにパブリック セッターを追加するList<T>ことは危険です。

しかし、危険な理由は記載されていません。そして、それは私が興味を持っている部分です。

このコレクションがある場合:

public List<Foo> Foos { get; set; }

セッターを非公開にする理由 どうやら、クライアント コードでコレクションを置き換えたくないようですが、クライアントがすべての要素を削除して、必要なものを追加できる場合、ポイントは何ですか? それはコレクションを完全に置き換えることと同じではありませんか? このコード分析ルールに従うことで、どのような価値が提供されるでしょうか?

4

5 に答える 5

9

セッターを公開しないことで、コレクションに値が割り当てられる状況を防ぐことができますnullnullと値のないコレクションには違いがあります。検討:

for (var value in this.myCollection){ // do something

値がない場合(つまり、誰かがRemoveすべての値を呼び出した場合)、悪いことは何も起こりません。this.myCollectionただし、がnullの場合、aNullReferenceExceptionがスローされます。

myCollectionコード分​​析は、コードを操作する前に、コードがnullをチェックしないことを前提としています。

これは、で定義されているスレッドセーフなコレクションタイプの追加の保護手段でもある可能性がありますSystem.Collections.Concurrent。コレクション全体を上書きして置き換えようとしているスレッドを想像してみてください。パブリックセッターを取り除くことにより、スレッドが持つ唯一のオプションは、スレッドセーフメソッドAddRemoveメソッドを呼び出すことです。

于 2012-07-05T17:34:49.410 に答える
2

IListを公開している場合(これはより良い方法です)、コンシューマーはコレクションをIListを実装するまったく異なるクラスに置き換えることができます。これは予測できない影響を与える可能性があります。そのコレクションのイベント、または現在誤って応答しているそのコレクションのアイテムのイベントをサブスクライブできた可能性があります。

于 2012-07-05T17:47:27.673 に答える
2

SimpleCoder の null チェック (これはもちろん重要です) に加えて、他にも考慮する必要があることがあります。

  • 誰かが List を置き換える可能性があり、スレッド セーフに大きな問題を引き起こす可能性があります
  • 置き換えられたリストへのイベントは、古いリストのサブスクライバーには送信されません
  • 必要以上に多くの動作を公開しています。たとえば、ゲッターを公開することさえしません。

ポイント3を明確にするために、 を実行せずcust.Orders.clear()、代わりに呼び出される関数を作成しますclearOrders()

顧客が与信限度額を超えることを許可されていない場合はどうなりますか? リストを公開すると、それを制御できなくなります。注文を追加する可能性のあるすべての場所 (および他のすべてのビジネス ロジック) を確認する必要があります。うわぁ!それはバグの可能性が非常に高いです。代わりに、すべてをaddOrder(Order o)関数に配置して、雨のようにすることができます。

ほぼすべてのビジネス クラス (すべてと言いたいところですが、不正行為が気持ちいい場合もあります...) では、すべてのプロパティを get と set に対して非公開にし、可能であれば読み取り専用にする必要があります。このようにして、クラスのユーザーは動作のみを取得します。できるだけ多くのデータを保護してください!

于 2012-07-05T17:54:57.153 に答える
1

ReadOnlyCollectionおよびReadOnlyObservableCollectionは、読み取り専用のコレクション シナリオに対してのみ存在します。

ReadOnlyObservableCollectionWPF/Silverlight/Metro アプリでの一方向バインディングに非常に役立ちます。

于 2012-07-05T17:39:20.683 に答える
0

List プロパティを持つ Customer クラスがある場合、このプロパティには常にプライベート セッターが必要です。そうでない場合は、次の方法で顧客オブジェクトの外部から変更できます。

customer.Orders = new List<Order> 
//this could overwrite data.

常にコレクションの add メソッドと remove メソッドを使用してください。

Orders List は、次の方法で Customer コンストラクター内に作成する必要があります。

Orders = new List<Order>();

コード内のすべての場所をチェックしてcustomer.Orders != nullから Orders を操作しますか?

または、顧客オブジェクトに Orders プロパティを提案どおりに作成し、チェックしないcustomer.Orders == null代わりに Orders を列挙するだけで、カウントがゼロの場合は何も起こりません...

于 2012-07-05T17:45:34.503 に答える