仅将唯一项添加到列表


84

我将远程设备添加到列表中,因为它们会在网络上宣布自己。我只想将设备添加到列表中(如果以前未添加过)。

这些通知是通过异步套接字侦听器传递的,因此添加设备的代码可以在多个线程上运行。我不确定自己做错了什么,但不管尝试什么,最终都会出现重复。这是我目前拥有的.....

lock (_remoteDevicesLock)
{
    RemoteDevice rDevice = (from d in _remoteDevices
                            where d.UUID.Trim().Equals(notifyMessage.UUID.Trim(), StringComparison.OrdinalIgnoreCase)
                            select d).FirstOrDefault();
     if (rDevice != null)
     {
         //Update Device.....
     }
     else
     {
         //Create A New Remote Device
         rDevice = new RemoteDevice(notifyMessage.UUID);
         _remoteDevices.Add(rDevice);
     }
}

它的定义是RemoteDevice什么?
pstrjds 2012年

出于调试目的,您可以使用时间戳字段_remoteDevices.lastSeen = now扩展_remoteDevices类吗?
Beth 2012年

Answers:


154

如果您的要求没有重复项,则应使用HashSet

当该项目已经存在时,HashSet.Add将返回false(即使这对您来说也很重要)。

您可以使用@pstrjds链接到以下(或此处)的构造函数来定义相等运算符,否则您将需要在RemoteDeviceGetHashCodeEquals)中实现相等方法。


3
即将添加此答案。您可以使用此重载定义比较- msdn.microsoft.com/en-us/library/bb359100(v=vs.100).aspx
pstrjds

11
这里要注意的重要一点是,不能保证HashSet遵守插入顺序。因此,如果顺序很重要(项目需要以与您放入它们时相同的顺序出现在列表中,例如发生的情况List<T>),则HashSet不能很好地工作。
JulianR 2012年

非常感谢。我还是需要保持锁的安全性,还是有更好的方法?
奥利(Oli)2012年

2
@Oli你需要保留锁,但操作会快,所以他们不会相互等待之多。ConcurrentSet不幸的是,没有课。但是有一个ConcurrentDictionary类,因此您可以使用该类,将您的值存储为键,然后只存储null在这些值中。
Servy

1
@Oli:如果我是您,我将发布另一个问题来解决该问题(带有GetHashCode和Equals的完整来源,以及在您不希望它们匹配时匹配的情况)。
奥斯丁·萨洛宁

22
//HashSet allows only the unique values to the list
HashSet<int> uniqueList = new HashSet<int>();

var a = uniqueList.Add(1);
var b = uniqueList.Add(2);
var c = uniqueList.Add(3);
var d = uniqueList.Add(2); // should not be added to the list but will not crash the app

//Dictionary allows only the unique Keys to the list, Values can be repeated
Dictionary<int, string> dict = new Dictionary<int, string>();

dict.Add(1,"Happy");
dict.Add(2, "Smile");
dict.Add(3, "Happy");
dict.Add(2, "Sad"); // should be failed // Run time error "An item with the same key has already been added." App will crash

//Dictionary allows only the unique Keys to the list, Values can be repeated
Dictionary<string, int> dictRev = new Dictionary<string, int>();

dictRev.Add("Happy", 1);
dictRev.Add("Smile", 2);
dictRev.Add("Happy", 3); // should be failed // Run time error "An item with the same key has already been added." App will crash
dictRev.Add("Sad", 2);

16

就像接受的答案说的那样,HashSet没有订单。如果订单很重要,则可以在添加之前继续使用列表并检查其中是否包含该项目。

if (_remoteDevices.Contains(rDevice))
    _remoteDevices.Add(rDevice);

在自定义类/对象上执行List.Contains()要求IEquatable<T>在自定义类上实现或覆盖Equals。同样GetHashCode在类中实现也是一个好主意。这是根据https://msdn.microsoft.com/zh-cn/library/ms224763.aspx上的文档

public class RemoteDevice: IEquatable<RemoteDevice>
{
    private readonly int id;
    public RemoteDevice(int uuid)
    {
        id = id
    }
    public int GetId
    {
        get { return id; }
    }

    // ...

    public bool Equals(RemoteDevice other)
    {
        if (this.GetId == other.GetId)
            return true;
        else
            return false;
    }
    public override int GetHashCode()
    {
        return id;
    }
}

嗨,谢谢,但是如果您因为我使用的是对他人代码的引用而无法覆盖该怎么办-在这里做什么?
BKSpurgeon '17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.