SortableBindingList,索引超出范围错误,如何使其线程安全
本文关键字:何使其 安全 错误 线程 范围 索引 SortableBindingList | 更新日期: 2023-09-27 18:01:08
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace MyApplication
{
public class SortableBindingList<T> : BindingList<T>
{
private static object syncLock = new object();
private readonly Dictionary<Type, PropertyComparer<T>> comparers;
private bool isSorted;
private ListSortDirection listSortDirection;
private PropertyDescriptor propertyDescriptor;
private System.ComponentModel.ISynchronizeInvoke _SyncObject;
private System.Action<System.ComponentModel.ListChangedEventArgs> _FireEventAction;
public SortableBindingList()
: base(new List<T>())
{
this.comparers = new Dictionary<Type, PropertyComparer<T>>();
}
public SortableBindingList(IEnumerable<T> enumeration, System.ComponentModel.ISynchronizeInvoke syncObject)
: base(new List<T>(enumeration))
{
_SyncObject = syncObject;
_FireEventAction = FireEvent;
this.comparers = new Dictionary<Type, PropertyComparer<T>>();
}
protected override bool SupportsSortingCore
{
get { return true; }
}
protected override bool IsSortedCore
{
get { return this.isSorted; }
}
protected override PropertyDescriptor SortPropertyCore
{
get { return this.propertyDescriptor; }
}
protected override ListSortDirection SortDirectionCore
{
get { return this.listSortDirection; }
}
protected override bool SupportsSearchingCore
{
get { return true; }
}
protected override void InsertItem(int index, T item)
{
lock (syncLock)
{
base.InsertItem(index, item);
}
}
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
{
List<T> itemsList = (List<T>)this.Items;
Type propertyType = property.PropertyType;
PropertyComparer<T> comparer;
if (!this.comparers.TryGetValue(propertyType, out comparer))
{
comparer = new PropertyComparer<T>(property, direction);
this.comparers.Add(propertyType, comparer);
}
comparer.SetPropertyAndDirection(property, direction);
itemsList.Sort(comparer);
this.propertyDescriptor = property;
this.listSortDirection = direction;
this.isSorted = true;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
protected override void RemoveSortCore()
{
this.isSorted = false;
this.propertyDescriptor = base.SortPropertyCore;
this.listSortDirection = base.SortDirectionCore;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
protected override int FindCore(PropertyDescriptor property, object key)
{
int count = this.Count;
for (int i = 0; i < count; ++i)
{
T element = this[i];
if (property.GetValue(element).Equals(key))
{
return i;
}
}
return -1;
}
protected override void OnListChanged(System.ComponentModel.ListChangedEventArgs args)
{
lock (syncLock)
{
if (_SyncObject == null)
{
FireEvent(args);
}
else
{
_SyncObject.Invoke(_FireEventAction, new object[] { args });
}
}
}
private void FireEvent(System.ComponentModel.ListChangedEventArgs args)
{
base.OnListChanged(args);
}
}
}
我得到以下错误:
指数超出范围。必须是非负数并且小于集合的大小。参数名称:index
- SortableBindingList绑定到DataGridView,虚拟模式
- 多个线程触发将数据添加到SortableBindingList的事件
private void ProxyScraper_OnProxyFound(Proxy Proxy, int Count)
{
ProxyProcessedCount.Text = Count.ToString();
_ProxyList.Add(Proxy);
}
我试图锁定SortableBindingList,但仍然出现错误,搜索了很多,但找不到解决方案。
最终,我怀疑制作一个真正线程安全的绑定列表是错误的,因为在某些情况下会执行多个操作——无论是"检查计数,然后将行迭代到计数-1"还是"使用foreach
枚举"——而且没有简单的方法来锁定这些操作的持续时间,因为调用代码超出了您的控制范围。
即使是半工作版本,您也需要通过覆盖所有可用方法,将syncLock
代码添加到每次访问中-然而,我在this[index]
上看不到get
的虚拟方法,这可能会使无效-只有当所有调用方都同意使用锁时,它才会同步。
最终,我怀疑尝试使用具有紧密UI耦合的线程是注定要失败的。IMO,您可能会更成功地将这两件事分开,并让UI担心处理事件和调用.Invoke(...)
来更新UI线程上的绑定。