Dodaj tylko unikalny przedmiot do listy


85

Dodaje zdalne urządzenia do listy, gdy ogłaszają się w sieci. Chcę tylko dodać urządzenie do listy, jeśli nie zostało wcześniej dodane.

Ogłoszenia przechodzą przez nasłuchiwacz gniazda asynchronicznego, więc kod dodawania urządzenia można uruchomić w wielu wątkach. Nie jestem pewien, co robię źle, ale bez względu na to, co próbuję, skończę z duplikatami. Oto, co mam obecnie .....

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);
     }
}

Jaka jest definicja RemoteDevice?
pstrjds

do celów debugowania, czy możesz rozszerzyć swoją klasę _remoteDevices o pole sygnatury czasowej _remoteDevices.lastSeen = now?
Beth

Odpowiedzi:


155

Jeśli twoje wymagania nie mają duplikatów, powinieneś używać HashSet .

HashSet.Add zwróci wartość false, gdy element już istnieje (jeśli to w ogóle ma dla Ciebie znaczenie).

Możesz użyć konstruktora, do którego link @pstrjds prowadzi poniżej (lub tutaj ), aby zdefiniować operator równości lub będziesz musiał zaimplementować metody równości w RemoteDevice( GetHashCode& Equals).


3
Miałem dodać tę odpowiedź. Możesz użyć tego przeciążenia do zdefiniowania porównania - msdn.microsoft.com/en-us/library/bb359100(v=vs.100).aspx
pstrjds

11
Ważna uwaga jest taka, że ​​HashSet nie gwarantuje przestrzegania kolejności reklamowej. Więc jeśli kolejność jest ważna (elementy muszą pojawiać się na liście w tej samej kolejności, w jakiej je umieściłeś, na przykład to, co się dzieje List<T>), HashSet nie działa dobrze.
JulianR

Wielkie dzięki za to. Czy nadal muszę trzymać zamek, aby zapewnić bezpieczeństwo gwintów, czy jest lepszy sposób?
Oli

2
@Oli Musisz trzymać zamek, ale operacja będzie znacznie szybsza, więc nie będą tak długo na siebie czekać. ConcurrentSetNiestety nie ma klasy. Istnieje jednak ConcurrentDictionaryklasa, więc możesz jej użyć, zapisać swoje wartości jako klucze i po prostu zachować nullwartości.
Servy

1
@Oli: Na twoim miejscu opublikowałbym kolejne pytanie, aby rozwiązać ten problem (z pełnym źródłem zarówno GetHashCode, jak i Equals, wraz z przypadkami, w których pasują do siebie, gdy się tego nie spodziewasz).
Austin Salonen

23
//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

Tak jak zaakceptowana odpowiedź mówi, że HashSet nie ma zamówienia. Jeśli zamówienie jest ważne, możesz nadal korzystać z listy i sprawdzić, czy zawiera przedmiot, zanim go dodasz.

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

Wykonywanie metody List.Contains () na niestandardowej klasie / obiekcie wymaga implementacji IEquatable<T>w klasie niestandardowej lub przesłaniania Equals. Warto również zaimplementować ją GetHashCodew klasie. Jest to zgodne z dokumentacją pod adresem 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;
    }
}

cześć, dzięki, ale co, jeśli nie możesz przesłonić, ponieważ używam odwołania do kodu innej osoby - co można tutaj zrobić?
BKSpurgeon
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.