我多次遇到这个设计问题,从未找到杀手解决方案。
我希望公开一个可在所有者class
范围内编辑的集合,但只能读取其他公共范围。
试用1:
public class MyClass
{
private List<object> _myList = new List<object>();
public IEnumerable<object> MyList { get { return _myList; } }
}
问题是外部代码可以将其强制转换回List
并进行编辑,如下所示:
var x = ((List<object>)MyList);
试用2:
public class MyClass
{
private List<object> _myList = new List<object>();
public IEnumerable<object> MyList { get { return _myList.ToList(); } }
}
这样我们就可以防止外部修改,但会多次复制List
会产生不必要的开销。
试用3:
public class MyClass
{
private List<object> _myList = new List<object>();
private ReadOnlyCollection<object> _roList =
new ReadOnlyCollection<object>(_myList)
public IEnumerable<object> MyList { get { return _roList; } }
}
这是我目前使用的标准解决方案,但ReadOnlyCollection
慢了约30%:
Debug Trace:
Use normal foreach on the ReadOnlyCollection
Speed(ms): 2520,3203125
Result: 4999999950000000
use<list>.ForEach
Speed(ms): 1446,1796875
Result: 4999999950000000
Use normal foreach on the List
Speed(ms): 1891,2421875
Result: 4999999950000000
是否有完美的&#39;这样做的方式?感谢。
答案 0 :(得分:6)
您是否尝试过返回枚举器?
public class MyClass
{
private List<object> _myList = new List<object>();
public IEnumerable<object> MyList { get { yield return _myList.GetEnumerator(); } }
}
这不会创建副本,只读,并且不能转换回列表。
修改:这仅适用于 yield 返回。以这种方式进行懒惰评估,我不知道这是否是一个问题。
答案 1 :(得分:3)
您可以使用List<T>.AsReadOnly
方法公开列表的精简只读包装。将不会有额外的复制,并且调用者将立即“看到”对方法内部完成的原始数组的更改:
public ReadOnlyCollection<object> MyList { get { return _myList.AsReadOnly(); } }
答案 2 :(得分:1)
我经常使用的解决方案很多,因为它很简单,如下所示:
public IEnumerable<object> MyList { get { return _myList.Select(x => x); } }
但是,它要求您使用支持Linq的.NET版本
使用foreach
进行循环时,它实际上更快:Select
小于1毫秒,ReadOnlyCollection
小于0.1秒。对于ReadOnlyCollection
,我使用了:
public IEnumerable<object> MyROList { get { return new ReadOnlyCollection<object>(_myList); } }
答案 3 :(得分:1)
v
实现List<T>
:
IReadOnlyList<T>
答案 4 :(得分:0)
使用ReadOnlyCollection<T>
作为包装器 - 它在内部使用您的List<T>
集合(使用相同的引用,因此它不会复制任何内容,对List的任何更改也会反映在ReadOnlyCollection中)。
它比提供IEnumerable属性更好,因为它还提供索引和计数信息。
答案 5 :(得分:0)
.NET Framework 4.5引入了两个新接口:IReadOnlyCollection<T>
和IReadOnlyList<T>
。 List<T>
实现了两个接口。
答案 6 :(得分:0)
为什么不使用List<T>.AsReadOnly
method,请参阅下面的代码段:
public class MyClass
{
private List<object> _myList = new List<object>();
public IList<object> MyList { get { return _myList.AsReadOnly(); } }
}