質問
これらのどれが最もクリーンであるか、使用するのに最適であると考えられるのか、そしてその理由は疑問です。
そのうちの1つは乗客のリストを公開し、これによりユーザーは追加や削除などを行うことができます。もう1つはリストを非表示にし、ユーザーがそれらを列挙して特別な方法で追加できるようにします。
例1
class Bus
{
public IEnumerable<Person> Passengers { get { return passengers; } }
private List<Passengers> passengers;
public Bus()
{
passengers = new List<Passenger>();
}
public void AddPassenger(Passenger passenger)
{
passengers.Add(passenger);
}
}
var bus = new Bus1();
bus.AddPassenger(new Passenger());
foreach(var passenger in bus.Passengers)
Console.WriteLine(passenger);
例2
class Bus
{
public List<Person> Passengers { get; private set; }
public Bus()
{
Passengers = new List<Passenger>();
}
}
var bus = new Bus();
bus.Passengers.Add(new Passenger());
foreach(var passenger in bus.Passengers)
Console.WriteLine(passenger);
私が言う最初のクラスは、カプセル化されたほうが良いです。そして、この正確なケースでは、それはより良いアプローチかもしれません(おそらくバスの空き容量などを確認する必要があるため)。しかし、2番目のクラスも同様に役立つ場合がありますか?クラスがリストを持っている限り、そのリストがどうなるかを本当に気にしない場合のように。どう思いますか?
解決
例1では、コレクションを変更できます。
次のことを考慮してください:
var passengers = (List<Passenger>)bus.Passengers;
// Now I have control of the list!
passengers.Add(...);
passengers.Remove(...);
これを修正するには、次のようなものを検討します:
class Bus
{
private List<Passenger> passengers;
// Never expose the original collection
public IEnumerable<Passenger> Passengers
{
get { return passengers.Select(p => p); }
}
// Or expose the original collection as read only
public ReadOnlyCollection<Passenger> ReadOnlyPassengers
{
get { return passengers.AsReadOnly(); }
}
public void AddPassenger(Passenger passenger)
{
passengers.Add(passenger);
}
}
他のヒント
ほとんどの場合、基になる型が拡張可能で、かつ/または何らかの形のonAdded / onRemovedイベントを公開して、内部クラスがコレクションへの変更に応答できる場合、例2を受け入れられると考えます。
この場合、List <!> lt; T <!> gt;クラスが何かが追加されたかどうかを知る方法がないため、適切ではありません。 Collection <!> lt; T <!> gt;ので、代わりにCollectionを使用する必要があります。クラスには、オーバーライド可能な複数の仮想メンバー(Insert、Remove、Set、Clear)があり、ラッピングクラスに通知するイベントトリガーが追加されます。
(クラスのユーザーは、親クラスに気付かれずにリスト/コレクション内のアイテムを変更できることにも注意する必要があります。したがって、変更されていないアイテムに依存しないようにしてください。明らかに不変です-または、必要に応じてonChangedスタイルのイベントを提供できます。)
FxCopを介してそれぞれの例を実行すると、List<T>
それはすべてあなたの状況にかかっていると思います。オプション2を選択するのが最も簡単なので、通常はオプション2を選択します。ビジネス上の理由でより厳密なコントロールを追加する必要がある場合を除きます。
オプション2は最も単純ですが、他のクラスがコレクションに要素を追加/削除できるようにするため、危険な場合があります。
良い発見的方法は、ラッパーメソッドが何をするかを考慮することだと思います。 AddPassenger(またはRemoveなど)メソッドがコレクションへの呼び出しを単純に中継している場合は、単純なバージョンを使用します。要素を挿入する前に 要素をチェックする必要がある場合、基本的にオプション1は避けられません。挿入/削除された要素を追跡する必要がある場合は、どちらの方法でも実行できます。オプション2では、コレクションにイベントを登録して通知を取得する必要があり、オプション1では、使用するリスト上のすべての操作(たとえば、挿入だけでなく追加も必要)のラッパーを作成する必要があるため、依存します。