如何防止在静态ObservableCollection线程安全中添加重复值?

时间:2010-06-25 18:41:15

标签: c# wpf thread-safety observablecollection

我不知道该怎么做才能管理此控件的_namePrefixes。我知道我可以把它变成非静态的,但是就我项目的内容而言,在这个控件的所有用途中保持一致是有意义的。此外,由于以下情况,我选择了ObservableCollection:

我有2台客户端计算机,一台用于标准用途,另一台用于管理选项(管理员),例如名称前缀列表。如果客户端正在运行且管理员进行了更改,则客户端应自行更新并在已加载后反映这些更改。哦,因为这是一个WPF项目,我想将它数据绑定到ListBox。如果这些都没有让我使用ObserableCollection,没什么大不了的...我会使用类似List的东西,但我认为这不会改变原来的问题。

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MyProject
{

    public class NameField : TextBox
    {
        private static ObservableCollection<NamePrefix> _namePrefixes;
        private static ObservableCollection<NameSuffix> _nameSuffixes;

        static NameField()
        {
            _namePrefixes = new ObservableCollection<NamePrefix>();
            _nameSuffixes = new ObservableCollection<NameSuffix>();
        }

        public static void AddNamePrefix(Int32 id, String prefix)
        {
            //TODO: WHAT DO I DO HERE!?
        }

    }

    /// <summary>
    /// A Key/Value structure containing a Name Prefix ID and String value.
    /// </summary>
    public struct NamePrefix
    {
        #region Constructor

        public NamePrefix(Int32 id, String prefix)
            : this()
        {
            ID = id;
            Prefix = prefix;
        }

        #endregion

        #region Properties (ID, Prefix)

        public Int32 ID { get; set; }
        public String Prefix { get; set; }

        #endregion
    }

    /// <summary>
    /// A Key/Value structure containing a Name Suffix ID and String value.
    /// </summary>
    public struct NameSuffix
    {
        #region Constructor

        public NameSuffix(Int32 id, String suffix)
            : this()
        {
            ID = id;
            Suffix = suffix;
        }

        #endregion

        #region Properties (ID, Prefix)

        public Int32 ID { get; set; }
        public String Suffix { get; set; }

        #endregion
    }
}

1 个答案:

答案 0 :(得分:2)

如果你想要做的是避免因为线程操作重叠而多次将相同的实际实例添加到集合中,那么标准的解决方案就是在lock块内部进行工作。

public static void AddNamePrefix(NamePrefix prefix)
{
    lock(_namePrefixes)
    {
        if(!_namePrefixes.Contains(prefix)) _namePrefixes.Add(prefix);
    }
}

(后缀相同)

锁是一次性资源,因此当一个线程锁定一个对象(在这种情况下是该集合)时,任何其他尝试获取该锁的线程都将被阻塞,直到释放现有锁。这种情况的结果是在任何给定时间只有一个线程能够执行锁定块内的代码;所有其他人将等到当前线程结束,然后一个接一个地继续。

值得注意的是,用于锁定的对象不必与块内发生的操作有任何关系。只要锁尝试锁定同一个对象,那么这将起作用。通常的做法是声明要锁定的object类型的专用实例,但在这种情况下,集合可以用于此目的。