リストに一意のアイテムのみを追加する


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クラスを拡張できますか?
ベス

回答:


154

要件に重複がないようにする場合は、HashSetを使用する必要があります。

アイテムがすでに存在する場合、HashSet.Addfalseを返します(それがあなたにとって重要な場合でも)。

@pstrjdsが以下(またはここ)にリンクするコンストラクターを使用して、等式演算子を定義できます。または、RemoteDeviceGetHashCodeEquals)に等式メソッドを実装する必要があります。


3
この答えを追加しようとしていました。-あなたは、比較を定義するには、このオーバーロードを使用することができますmsdn.microsoft.com/en-us/library/bb359100(v=vs.100).aspx
pstrjds

11
ここで重要なのは、HashSetが挿入順序を尊重することは保証されていないということです。したがって、順序が重要な場合(アイテムは、で発生するように、アイテムを配置したのと同じ順序でリストに表示される必要がありますList<T>)、HashSetはうまく機能しません。
JulianR 2012年

これに感謝します。スレッドセーフのためにロックを維持する必要がありますか、それともより良い方法がありますか?
オリ2012年

2
@Oliロックを維持する必要がありますが、操作がはるかに高速になるため、お互いを待つことはあまりありません。ConcurrentSet残念ながら授業はありません。ただし、ConcurrentDictionaryクラスがあるので、それを使用して、値をキーとして保存し、値に保存することができnullます。
Servy 2012年

1
@Oli:もし私があなたなら、その問題に対処するために別の質問を投稿します(GetHashCodeとEqualsの両方の完全なソースと、予期しないときに一致する場合)。
オースティンサロネン2012年

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>には、カスタムクラスに実装するか、をオーバーライドする必要がありますEqualsGetHashCodeクラスにも実装することをお勧めします。これは、https://msdn.microsoft.com/en-us/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;
    }
}

こんにちはthxですが、他の誰かのコードへの参照を使用しているためにオーバーライドできない場合はどうなりますか?ここでは何をしますか?
BKSpurgeon 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.