题
我想知道其中这些中的一个将被认为是干净的或最好用和原因。
其中之一暴露出乘客列表,其中让用户添加和删除等其他隐藏列表,并只让用户枚举并添加使用一种特殊的方法。
实施例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);
我想说的第一类是更好封装。而在这种情况下准确,这可能是更好的方法(因为你应该确保它留在公共汽车上空间等)。但我想有可能是情况下,第二类可能是有用的呢?就像如果类并不真正关心,只要它有一个上发生了什么名单。你觉得呢?
解决方案
在例如一个,有可能发生变异的集合。
考虑如下:
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);
}
}
其他提示
在大多数情况下,我会考虑实施例2是可以接受的条件是基础类型是可扩展的和/或暴露的某种形式的onAdded回调函数里/ onRemoved事件,以便内部类可以以任何更改到集合做出响应。
在这种情况下,列表
(你也必须意识到类的用户可以修改列表/集合中的项目,而不父类不了解它,所以请确保您不依赖于项目是不变的 - 除非他们是不可变的很明显 - 或者,如果你需要,你可以提供风格调用onChanged事件)
通过FxCop的运行您的实例和应该给你揭露List<T>
的风险提示
我会说这一切都归结到你的情况。我通常会去选择2,因为它是最简单的,除非的你有一个企业的理由更严格的控件添加到它。
选项2是最简单的,但可以让其他的类来添加/删除元素的收集,这可能是危险的。
我认为一个好的启发式是要考虑什么样的包装方法做。如果您AddPassenger(或删除,或其他)方法简单地中继调用集合,然后我会去的简化版本。如果你要检查的元素之前的插入它们,然后选择1基本上是不可避免的。如果你有跟踪插入/删除的元素,你可以去任何一种方式。对于选项2,你必须注册在收集事件得到通知,并与选项1,你必须为你想使用(例如,如果你想插入以及添加),所以我想在名单上的每个操作创建包装这取决于