在C#中,当我想封装一个List时,我会把它放在一个类中,并在其中抛出一些helper方法。然而,我注意到,每当我想迭代项目列表时,我只会返回列表。易于理解的然而,糟糕的是,我无法判断列表是否被错误的方法修改了。
这就是我一直在做的事情:
class Animals
{
private List<Dog> _dogs;
public List<Dog> Dogs
{
get { return _dogs; }
}
}
为了反驳这一点,我想做:
class Animals
{
private List<Dog> _dogs;
public Dog GetDog(int dogid)
{
return _dogs[dogid];
}
public int Count
{
get { return _dogs.Count; }
}
}
这个方法的真正问题在于,每次我想要列表中的一个项时,都必须调用一个方法。这意味着,如果我想对列表进行迭代,我必须设置一个循环,以在每次迭代中调用Animals.GetDog(i)
的次数为Animals.Count
。
这会影响我的节目吗?有没有更合适的方法来完成同样的事情?
我已经研究过封装列表的方法,但它们看起来相当复杂。我的主要目标是不将_dogs
列表公开给类之外的任何东西。
您可以很容易地使用IEnumerable来封装列表:
public IEnumerable<Dog> GetDogs()
{
foreach (Dog dog in _dogs)
{
yield return dog;
}
}
这允许您从类外部枚举列表,但不能访问基础列表。
//Outside Animals class
foreach (Dog dog in animalObj.GetDogs())
{
//do stuff
}
您可以返回ReadOnlyCollection
而不是List
:
public class Animals
{
public Animals()
{
myModifiableDogList = new List<Dog>();
Dogs = new ReadOnlyCollection<Dog>(myModifiableDogList);
}
private IList<Dog> myModifiableDogList;
public ReadOnlyCollection<Dog> Dogs { get; private set; }
}
通过这种方式,您可以对列表进行更改,而不允许其他访问Dogs
属性的人对其进行更改。这也允许用户始终拥有更新的集合,而不是始终返回列表的副本。
解决问题的一种非常常见的方法是返回列表的只读快照,例如
public ReadOnlyCollection<Dog> Snapshot
{
get
{
return new ReadOnlyCollection<Dog>(_dogs);
}
}