【发布时间】:2014-01-08 00:46:09
【问题描述】:
假设我有 IEnumerable<int> 属性支持 List<int> 字段,所以我可以在类中修改集合,但它公开为只读。
public class Foo
{
private List<int> _bar = new List<int>();
public IEnumerable<int> Bar
{
get { return _bar; }
}
}
但是使用这样的代码,您可以轻松地将从属性中检索到的对象转换回 List<int> 并对其进行修改:
var foo = new Foo();
var bar = (List<int>)foo.Bar;
bar.Add(10);
问题是:什么是最好的(最好的可读性,最容易编写,没有性能损失)避免这种情况的方法?
我可以想出至少 4 个解决方案,但没有一个是完美的:
-
foreach和yield return:public IEnumerable<int> Bar { get { foreach (var item in _bar) yield return item; } }- 写和读真的很烦人。
-
AsReadOnly():
当有人试图修改返回的集合时,public IEnumerable<int> Bar { get { return _bar.AsReadOnly(); } }+ 会引发异常
+ 不会创建整个集合的副本。 -
ToList()public IEnumerable<int> Bar { get { return _bar.ToList(); } }+ 用户仍然可以修改检索到的集合,但它与我们在类中修改的集合不同,所以我们不应该关心。
- 创建整个集合的副本,当集合很大时可能会导致问题。 -
自定义包装器类。
public static class MyExtensions { private class MyEnumerable<T> : IEnumerable<T> { private ICollection<T> _source; public MyEnumerable(ICollection<T> source) { _source = source; } public IEnumerator<T> GetEnumerator() { return _source.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_source).GetEnumerator(); } } public static IEnumerable<T> AsMyEnumerable<T>(this ICollection<T> source) { return new MyEnumerable<T>(source); } }用法:
public IEnumerable<int> Bar { get { return _bar.AsMyEnumerable(); } }+ 不需要克隆集合
- 当您将其用作 LINQ 查询源时,某些方法不会使用ICollection.Count,因为您不要暴露它。
有没有更好的方法来做到这一点?
【问题讨论】:
-
2 和 4 似乎几乎相同,而且这个问题似乎是基于意见的(并且:基于上下文的又过于宽泛)。
-
我通常使用 (ReadOnlyCollection
)msdn.microsoft.com/en-us/library/ms132474(v=vs.110).aspx 它已准备好使用标准类来包装您的列表。 -
@PetkoPetkov 这就是他的选项 2 已经做的......
标签: c# list ienumerable