C# 如何允许在私有集合上进行迭代,但不允许修改?
如果我有以下班级成员:C# 如何允许在私有集合上进行迭代,但不允许修改?,c#,design-patterns,iterator,C#,Design Patterns,Iterator,如果我有以下班级成员: private List<object> obs; 我想允许遍历这个列表作为类接口的一部分,我该怎么做 将其公开是行不通的,因为我不想直接修改列表。您是否考虑过从System.Collections.ReadOnlyCollectionBase派生类?您会将其公开为IEnumerable,而不仅仅是直接返回它: public IEnumerable<object> Objects { get { return obs.Select(o =>
private List<object> obs;
我想允许遍历这个列表作为类接口的一部分,我该怎么做
将其公开是行不通的,因为我不想直接修改列表。您是否考虑过从System.Collections.ReadOnlyCollectionBase派生类?您会将其公开为IEnumerable,而不仅仅是直接返回它:
public IEnumerable<object> Objects { get { return obs.Select(o => o); } }
因为您表示只希望遍历列表,所以这就是您所需要的
您可能会试图直接将列表作为IEnumerable返回,但这是不正确的,因为您可以在运行时轻松地检查IEnumerable,确定它是一个列表,并将其强制转换为这样的列表,并改变内容
但是,通过使用return obs.Selecto=>o;最终返回列表的迭代器,而不是对列表本身的直接引用
有些人可能认为,根据C语言规范第7.15.2.5节,这符合退化表达式的条件。然而
此外,人们建议人们使用。这是不正确的,因为保留了原始列表的参考标识。从文件的备注部分:
AsEnumerable IEnumerable方法的作用只是将源代码的编译时类型从实现IEnumerable的类型更改为IEnumerable本身。
换句话说,它所做的只是将源参数强制转换为IEnumerable,这无助于保护引用完整性,原始引用将被返回,并可以回溯到列表中,用于修改列表。考虑到复制操作的性能损失,您可以使用或复制列表并返回它。您还可以使用。公开只读集合您可以通过以下两种方式执行此操作:
private List<object> objs;
public ReadOnlyCollection<object> Objs {
get {
return objs.AsReadOnly();
}
}
通过将列表转换为只读集合:
new System.Collections.ObjectModel.ReadOnlyCollection<object>(this.obs)
关于这个问题的有趣帖子和对话框:。在您的界面上添加以下方法签名: 公共IEnumerable遍历列表 实施如下:
public IEnumerable<object> TraverseTheList()
{
foreach( object item in obj)
{
yield return item;
}
}
yield返回告诉编译器为您构建一个枚举器。这已经说过了,但我不认为任何答案是超级清晰的 最简单的方法是简单地返回ReadOnlyCollection
private List<object> objs;
public ReadOnlyCollection<object> Objs {
get {
return objs.AsReadOnly();
}
}
这样做的缺点是,如果以后要更改实现,则某些调用方可能已经依赖于集合提供随机访问这一事实。因此,更安全的定义是只公开IEnumerable
public IEnumerable<object> Objs {
get {
return objs.AsReadOnly();
}
}
请注意,编译此代码不必调用AsReadOnly。但如果您不这样做,调用方my只需将返回值转换回列表并修改您的列表
// Bad caller code
var objs = YourClass.Objs;
var list = objs as List<object>;
list.Add(new object); // They have just modified your list.
这种解决方案也存在同样的潜在问题
public IEnumerable<object> Objs {
get {
return objs.AsEnumerable();
}
}
所以我强烈建议您在列表中调用AsReadOnly,并返回该值。只需返回一个
让发问者四处打听并不是什么问题。Google上的第一个结果表明了如何公开ReadOnlyCollection。我只承认@Mitch Wheat应该包含一个指向MSDN页面的链接。如果继续,我们只会复制MSDN页面上的内容。简单+安全的完美组合。请注意,如果代码中出现了选择,我们永远不会优化掉显式调用。在将查询表达式转换为方法调用时,我们将优化掉要选择的隐式调用。如果你说从y中的x选择x,没有选择调用,只有一个where。但若你们说从x到y选择x,那个么我们不仅仅生成y,我们还对它生成一个选择调用,以确保结果的不变性。
public IEnumerable<object> Objs {
get {
return objs.AsEnumerable();
}
}
private List<object> obs;
IReadOnlyCollection<object> GetObjects()
{
return obs;
}