我创建了这个特定的集合类:
public class RangeObservableCollection<T> : ObservableCollection<T>
{
private bool _suppressNotification = false;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
try
{
if (!_suppressNotification)
base.OnCollectionChanged(e);
}
catch
{
}
}
public void AddRange(IEnumerable<T> list)
{
if (list == null) {
return ;
}
_suppressNotification = true;
foreach (T item in list)
{
Add(item);
}
_suppressNotification = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void EditElement(int index, object value)
{
_suppressNotification = true;
if (index >= 0 && index < this.Count) this[index] = (T)value;
_suppressNotification = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void RemoveElementAt(int index)
{
_suppressNotification = true;
if (index >= 0 && index < this.Count) this.RemoveAt(index);
_suppressNotification = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void RemoveElement(T element)
{
_suppressNotification = true;
this.Remove(element);
_suppressNotification = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
然后我想像这样使用它:
public RangeObservableCollection<vue_medecin > MedecinGDP { get; set; }
public RangeObservableCollection<gdp_groupe > CodeGDP_Collection { get; set; }
public RangeObservableCollection<fsign_fiche > FiltredParticipant { get; set; }
private async Task FillList()
{
await Task.Factory.StartNew(() =>
{
gdpList = SimpleIoc.Default.GetInstance<ICrud<gdp_groupe>>().GetAll().ToList();
MedecinGDP.AddRange(SimpleIoc.Default.GetInstance<ICrud<vue_medecin>>().GetAll());
CodeGDP_Collection.AddRange(gdpList);
FiltredParticipant.AddRange(SimpleIoc.Default.GetInstance<ICrud<fsign_fiche>>().GetAll());
});
}
我想自定义RangeObservableCollection
以使其成为线程安全的,因为在我的情况下,主线程和任务之间的并发访问可能会导致问题。
我想避免使用并发集合(如here所述),因为我必须在我的程序中使用此集合类型。
那么,如何编辑此实现来完成此任务?最好的想法是什么?
谢谢,
答案 0 :(得分:2)
如果我理解正确,你只有一个线程修改集合,只是想确保读者可以安全地访问它。
如果是这样,您可以让后台线程计算新元素,但调度会将元素添加到读者线程中。这有效地使变异/读取全部发生在同一线程上,避免了同步问题。我相信这是Servy在评论中提出的建议。
如果您正在从UI线程中读取,这是最简单的,因为您可以使用标准的调度机制。 Async / await使得这一点变得特别简单(假设从UI线程调用FillList):
private async Task FillList()
{
gdpList = await Task.Run(() => SimpleIoc.Default.GetInstance<ICrud<gdp_groupe>>().GetAll().ToList());
MedecinGDP.AddRange(await Task.Run(() => SimpleIoc.Default.GetInstance<ICrud<vue_medecin>>().GetAll()));
CodeGDP_Collection.AddRange(gdpList);
FiltredParticipant.AddRange(await Task.Run(() => SimpleIoc.Default.GetInstance<ICrud<fsign_fiche>>().GetAll()));
}
答案 1 :(得分:1)
我通常使用
private readonly object m_lock = new object();
每次访问您的方法时,请执行以下操作:
lock(m_lock){
// your code goes here
}
使用它将确保一次只有一个线程可以访问这段代码。希望这有帮助
答案 2 :(得分:1)
您无法使此自定义集合成为线程安全的,因为它继承自非线程安全的类。您可以使一些方法成为线程安全的(您可以覆盖的方法或您自己编写的方法)但不是所有方法(并非基类的所有成员都是虚拟的)。
如果您希望创建一个线程安全的自定义集合,您应该继承System.Collections.Concurrent命名空间中的一个类。
另一个选择是使用容器方法而不是继承,例如编写一个线程安全的包装器而不是一个后代类。