标签:
最近在做windows runtime下APP开发的工作。在Service层请求返回后,往往会通过回调的形式来通知UI更新数据。多个线程操作经常出现foreach抛出异常:System.InvalidOperationException: 集合已修改;可能无法执行枚举操作,导致APP crash。
在网上搜索了一下,得出以下结论:
以下是一个最小化实现的枚举安全的List。因为实际工程中,需要枚举安全的集合仅用到了Add,Count,索引等操作,所以继承了IEnumerable接口,而不是IList。同时也不影响使用Linq to objects的扩展方法,真是偷了一个大懒。
class EnumerationSafeList<T> : IEnumerable<T> { private List<T> innerList = new List<T>(); private object lockObject = new object(); public IEnumerator<T> GetEnumerator() { return Clone().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return Clone().GetEnumerator(); } public void Add(T item) { lock(lockObject) { innerList.Add(item); } } public void Remove(T item) { lock(lockObject) { innerList.Remove(item); } } public int Count { get { lock(lockObject) { return innerList.Count; } } } public T this[int index] { get { lock(lockObject) { return innerList[index]; } } set { lock(lockObject) { innerList[index] = value; } } } private List<T> Clone() { var cloneList = new List<T>(); lock(lockObject) { foreach (var item in innerList) { cloneList.Add(item); } } return cloneList; } }
代码对Add,Remove,Count和索引四个操作加了lock,同时在枚举时通过加lock并返回当前集合的副本,来避免遍历时因为其他线程的修改而抛出异常。
如果代码需要List类型的全部方法,就需要进一步修改,把IEnumerable改成IList并实现接口,就可以得到一个完整的“data thread safe list”。
完整的代码及测试用的程序:代码
标签:
原文地址:http://www.cnblogs.com/manupstairs/p/4870187.html