Только Добавить Уникальный Элемент В Список


Я добавляю удаленные устройства в список, когда они объявляют себя по сети. Я только хочу добавить устройство в список, если оно ранее не было добавлено.

объявления приходят через прослушиватель асинхронного сокета, поэтому код для добавления устройства может быть запущен в нескольких потоках. Я не уверен, что я делаю неправильно, но независимо от того, что я пытаюсь, я в конечном итоге с дубликатами. Вот что у меня сейчас есть.....

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

4 ответа:

Если ваши требования не должны иметь дубликатов, вы должны использовать HashSet.

HashSet.Добавить вернутся ложные когда элемент уже существует (если это даже имеет значение для вас).

вы можете использовать конструктор, на который @pstrjds ссылается ниже (или здесь) для определения оператора равенства или вам нужно будет реализовать методы равенства в RemoteDevice (GetHashCode & Equals).

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

так же, как принятый ответ говорит, что хэш-набор не имеет порядка. Если заказ важен, вы можете продолжить использовать список и проверить, содержит ли он элемент, прежде чем добавлять его.

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

Список Выполнения.Содержит () для пользовательского класса/объекта требуется реализация IEquatable<T> на пользовательский класс или переопределение Equals. Это хорошая идея, чтобы также реализовать GetHashCode в классе тоже. Это в документации по 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;
    }
}

может быть записан как метод расширения, чтобы получить некоторую общность, и вы можете передать дополнительный пользовательский компаратор...

/// <summary>
/// Generates a new list with only distinct items preserving original ordering.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static IList<T> ToUniqueList<T>(this IList<T> list, IEqualityComparer<T> comparer = null)
{
    bool Contains(T x) => comparer == null ? list.Contains(x) : list.Contains(x, comparer);

    return list.Where(entity => !Contains(entity)).ToList();
}