如果我有以下班级成员:
private List<object> obs;
我希望允许遍历此列表作为类'界面的一部分,我该怎么做?
将其公开将无效,因为我不想直接修改列表。
答案 0 :(得分:13)
您会将其公开为IEnumerable<T>
,但不会直接将其公开:
public IEnumerable<object> Objects { get { return obs.Select(o => o); } }
由于您表示您只想要列表的遍历,这就是您所需要的。
有人可能会试图直接将List<object>
作为IEnumerable<T>
返回,但这是不正确的,因为可以在运行时轻松检查IEnumerable<T>
,确定它是List<T>
1}}并将其转换为内容。
但是,使用return obs.Select(o => o);
最终会在List<object>
上返回迭代器,而不是直接引用List<object>
本身。
根据C#语言规范的第7.15.2.5节,有些人可能会认为这符合“退化表达式”。但是,Eric Lippert goes into detail as to why this projection isn't optimized away。
此外,人们建议使用AsEnumerable extension method。这是不正确的,因为维护了原始列表的引用标识。从文档的备注部分:
除了将源代码的编译时类型从实现AsEnumerable<TSource>(IEnumerable<TSource>)
的类型更改为IEnumerable<T>
本身之外,IEnumerable<T>
方法无效。
换句话说,它只是将源参数强制转换为IEnumerable<T>
,这无助于保护参照完整性,返回原始引用并可以转换回List<T>
并使用改变名单。
答案 1 :(得分:11)
您可以使用ReadOnlyCollection
或复制List
并将其返回(考虑到复制操作的性能损失)。您也可以使用List<T>.AsReadOnly
。
答案 2 :(得分:3)
这已经说过了,但我没有看到任何答案是否过于清晰。
最简单的方法是简单地返回一个ReadOnlyCollection
private List<object> objs;
public ReadOnlyCollection<object> Objs {
get {
return objs.AsReadOnly();
}
}
这样做的缺点是,如果您想稍后更改您的实现,那么一些调用者可能已经依赖于该集合提供随机访问的事实。因此更安全的定义是公开IEnumerable
public IEnumerable<object> Objs {
get {
return objs.AsReadOnly();
}
}
请注意,您不必调用AsReadOnly()来编译此代码。但是如果你不这样做,调用者我只是将返回值强制转换回List并修改你的列表。
// 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()并返回该值。
答案 3 :(得分:2)
您可以通过两种方式执行此操作:
通过将列表转换为Readonly集合:
new System.Collections.ObjectModel.ReadOnlyCollection<object>(this.obs)
或者通过返回IEnumerable项目:
this.obs.AsEnumerable()
答案 4 :(得分:2)
在您的界面中添加以下方法签名: public IEnumerable TraverseTheList()
如此I:
public IEnumerable<object> TraverseTheList()
{
foreach( object item in obj)
{
yield return item;
}
}
允许您执行以下操作:
foreach(object item in Something.TraverseTheList())
{
// do something to the item
}
yield return告诉编译器为你构建一个枚举器。
答案 5 :(得分:1)
公开ReadOnlyCollection<T>
答案 6 :(得分:1)
答案 7 :(得分:0)
您是否考虑过从System.Collections.ReadOnlyCollectionBase派生一个类?
答案 8 :(得分:0)
只需返回一个 IReadOnlyCollection
。
private List<object> obs;
IReadOnlyCollection<object> GetObjects()
{
return obs;
}