无法在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);