无法在C#ConcurrentDictionary上调用PropertyChanged事件
我试图在无法在C#ConcurrentDictionary上调用PropertyChanged事件,c#,event-handling,concurrentdictionary,C#,Event Handling,Concurrentdictionary,我试图在C#中使用ConcurrentDictionary并在字典中添加新项目时处理事件,但我无法这样做,代码如下 public class TopicTaskConcurrentDictionary { #region Singleton private static volatile ConcurrentDictionary<KeyValuePair<string, string>, IDataPipesService> _in
C#
中使用ConcurrentDictionary
并在字典中添加新项目时处理事件,但我无法这样做,代码如下
public class TopicTaskConcurrentDictionary
{
#region Singleton
private static volatile ConcurrentDictionary<KeyValuePair<string, string>, IDataPipesService> _instance;
private static readonly object Sync = new object();
private static readonly object Lock = new object();
public static event EventHandler PropertyChanged;
public static ConcurrentDictionary<KeyValuePair<string, string>, IDataService> Instance
{
get
{
if (_instance != null) return _instance;
lock (Sync)
{
if (_instance == null)
{
_instance = new ConcurrentDictionary<KeyValuePair<string, string>, IDataService>();
}
}
return _instance;
}
}
#endregion Singleton
public void TryAdd(KeyValuePair<string, string> keyValuePair, IDataPipesService service) {
Instance.TryAdd(keyValuePair, service);
PropertyChanged(null, EventArgs.Empty);
}
}
当我执行上述操作时,
PropertyChanged
事件从未被调用,我可以知道我哪里出错了吗?您遇到了封装问题。似乎您已经实现了错误的单例模式。您正在向客户端代码公开基础集合。它绕过了主题AskConcurrentDictionary
逻辑。这就是为什么你的活动从未被提起。实际上,您调用的是concurrentdiction.TryAdd
,而不是topictaskconcurrentdiction.TryAdd
您正在将新项直接添加到基础集合中。
要修复代码,请删除实例
属性或正确实现单例。但这两个版本至少应该实现IEnumerable
接口
我将PropertyChanged
替换为CollectionChanged
(在绑定场景中启用observedcollection
行为),并添加了IEnumerable.GetEnumerator()
的实现,以使集合能够在foreach
迭代中使用。然后我正确地实现了单例模式。通过使用Lazy
,您可以减少创建单个共享线程安全实例的代码:
public sealed class TopicTaskConcurrentDictionary : IEnumerable, IEnumerable<KeyValuePair<KeyValuePair<string, string>, IDataPipesService>>
{
public static TopicTaskConcurrentDictionary Instance =>
TopicTaskConcurrentDictionary._instance.Value;
public event NotifyCollectionChangedEventHandler CollectionChanged;
private ConcurrentDictionary<KeyValuePair<string, string>, IDataPipesService> underlyingCollection;
private static readonly object Sync = new object();
private static readonly Lazy<TopicTaskConcurrentDictionary> _instance =
new Lazy<TopicTaskConcurrentDictionary>(() => new TopicTaskConcurrentDictionary());
private TopicTaskConcurrentDictionary()
{
this.underlyingCollection = new ConcurrentDictionary<KeyValuePair<string, string>, IDataPipesService>();
}
public void TryAdd(KeyValuePair<string, string> key, IDataPipesService value)
{
this.underlyingCollection.TryAdd(key, value);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new KeyValuePair<KeyValuePair<string, string>, IDataPipesService>(key, value)));
}
public IEnumerator<KeyValuePair<KeyValuePair<string, string>, IDataPipesService>> GetEnumerator()
{
foreach (KeyValuePair<KeyValuePair<string, string>, IDataPipesService> entry in this.underlyingCollection)
{
yield return entry;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
this.CollectionChanged?.Invoke(this, e);
}
}
您遇到了封装问题。似乎您已经实现了错误的单例模式。您正在向客户端代码公开基础集合。它绕过了
主题AskConcurrentDictionary
逻辑。这就是为什么你的活动从未被提起。实际上,您调用的是concurrentdiction.TryAdd
,而不是topictaskconcurrentdiction.TryAdd
您正在将新项直接添加到基础集合中。
要修复代码,请删除实例
属性或正确实现单例。但这两个版本至少应该实现IEnumerable
接口
我将PropertyChanged
替换为CollectionChanged
(在绑定场景中启用observedcollection
行为),并添加了IEnumerable.GetEnumerator()
的实现,以使集合能够在foreach
迭代中使用。然后我正确地实现了单例模式。通过使用Lazy
,您可以减少创建单个共享线程安全实例的代码:
public sealed class TopicTaskConcurrentDictionary : IEnumerable, IEnumerable<KeyValuePair<KeyValuePair<string, string>, IDataPipesService>>
{
public static TopicTaskConcurrentDictionary Instance =>
TopicTaskConcurrentDictionary._instance.Value;
public event NotifyCollectionChangedEventHandler CollectionChanged;
private ConcurrentDictionary<KeyValuePair<string, string>, IDataPipesService> underlyingCollection;
private static readonly object Sync = new object();
private static readonly Lazy<TopicTaskConcurrentDictionary> _instance =
new Lazy<TopicTaskConcurrentDictionary>(() => new TopicTaskConcurrentDictionary());
private TopicTaskConcurrentDictionary()
{
this.underlyingCollection = new ConcurrentDictionary<KeyValuePair<string, string>, IDataPipesService>();
}
public void TryAdd(KeyValuePair<string, string> key, IDataPipesService value)
{
this.underlyingCollection.TryAdd(key, value);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new KeyValuePair<KeyValuePair<string, string>, IDataPipesService>(key, value)));
}
public IEnumerator<KeyValuePair<KeyValuePair<string, string>, IDataPipesService>> GetEnumerator()
{
foreach (KeyValuePair<KeyValuePair<string, string>, IDataPipesService> entry in this.underlyingCollection)
{
yield return entry;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
this.CollectionChanged?.Invoke(this, e);
}
}
item.Value.IsRunning不是集合的属性。您需要处理items上的PropertyChanged。item.Value.IsRunning不是集合的属性。您需要处理项目的属性更改。谢谢!如何遍历
TopicTaskConcurrentDictionary中的每个值。实例
,项。值
不再有效,实例也不再有效。有没有办法让我像收藏一样使用这些东西?你是什么意思?它在示例中。您可以使用foreach
item
在其中只包含Equals、GetHashCode、GetType和ToString
。这是因为集合只实现了IEnumerable
。因此,foreach
返回的项属于object类型,在使用它们之前需要强制转换。我更新了答案TopicTaskConcurrentDictionary
现在实现了IEnumerable
。现在你可以像你期望的那样使用它,不用铸造。谢谢!如何遍历TopicTaskConcurrentDictionary中的每个值。实例
,项。值
不再有效,实例也不再有效。有没有办法让我像收藏一样使用这些东西?你是什么意思?它在示例中。您可以使用foreach
item
在其中只包含Equals、GetHashCode、GetType和ToString
。这是因为集合只实现了IEnumerable
。因此,foreach
返回的项属于object类型,在使用它们之前需要强制转换。我更新了答案TopicTaskConcurrentDictionary
现在实现了IEnumerable
。现在,您可以像预期的那样使用它,而无需铸造。
public sealed class TopicTaskConcurrentDictionary : IEnumerable, IEnumerable<KeyValuePair<KeyValuePair<string, string>, IDataPipesService>>
{
public static TopicTaskConcurrentDictionary Instance =>
TopicTaskConcurrentDictionary._instance.Value;
public event NotifyCollectionChangedEventHandler CollectionChanged;
private ConcurrentDictionary<KeyValuePair<string, string>, IDataPipesService> underlyingCollection;
private static readonly object Sync = new object();
private static readonly Lazy<TopicTaskConcurrentDictionary> _instance =
new Lazy<TopicTaskConcurrentDictionary>(() => new TopicTaskConcurrentDictionary());
private TopicTaskConcurrentDictionary()
{
this.underlyingCollection = new ConcurrentDictionary<KeyValuePair<string, string>, IDataPipesService>();
}
public void TryAdd(KeyValuePair<string, string> key, IDataPipesService value)
{
this.underlyingCollection.TryAdd(key, value);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new KeyValuePair<KeyValuePair<string, string>, IDataPipesService>(key, value)));
}
public IEnumerator<KeyValuePair<KeyValuePair<string, string>, IDataPipesService>> GetEnumerator()
{
foreach (KeyValuePair<KeyValuePair<string, string>, IDataPipesService> entry in this.underlyingCollection)
{
yield return entry;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
this.CollectionChanged?.Invoke(this, e);
}
}
TopicTaskConcurrentDictionary.Instance.CollectionChanged += delegate (object o, NotifyCollectionChangedEventArgs e)
{
foreach (KeyValuePair<KeyValuePair<string, string>, IDataPipesService> item in TopicTaskConcurrentDictionary.Instance)
{
;
}
};
var dataService = _kernel.Get<IDataService>();
TopicTaskConcurrentDictionary.Instance.TryAdd(new KeyValuePair<string, string>(param.TagPrefix, param.TopicName), dataService);