Подтвердить что ты не робот

Что использует Collection.Contains() для проверки существующих объектов?

У меня есть строго типизированный список пользовательских объектов MyObject, у которого есть идентификатор свойства вместе с некоторыми другими свойствами.
Скажем, что Id из MyObject определяет его как уникальное, и я хочу проверить, не имеет ли моя коллекция еще объекта MyObject, который имеет идентификатор 1, прежде чем я добавлю новый MyObject в коллекцию.
Я хочу использовать if (! List.Contains(myObj)), но как я могу применить тот факт, что только одно или два свойства MyObject определяют его как уникальное?
Я могу использовать IComparable? Или мне нужно только переопределить метод Equals, но мне нужно сначала наследовать что-то в этом роде?



Спасибо

4b9b3361

Ответ 1

List<T>.Contains использует EqualityComparer<T>.Default, который, в свою очередь, использует IEquatable<T>, если тип реализует его, или object.Equals в противном случае.

Вы могли бы просто реализовать IEquatable<T>, но это хорошая идея переопределить object.Equals, если вы это сделаете, и очень хорошая идея переопределить GetHashCode(), если вы это сделаете:

public class SomeIDdClass : IEquatable<SomeIDdClass>
{
    private readonly int _id;
    public SomeIDdClass(int id)
    {
        _id = id;
    }
    public int Id
    {
        get { return _id; }
    }
    public bool Equals(SomeIDdClass other)
    {
        return null != other && _id == other._id;
    }
    public override bool Equals(object obj)
    {
        return Equals(obj as SomeIDdClass);
    }
    public override int GetHashCode()
    {
        return _id;
    }
}

Обратите внимание, что хеш-код относится к критериям равенства. Это важно.

Это также делает его применимым для любого другого случая, когда равенство, определенное с помощью того же идентификатора, полезно. Если у вас есть одно требование проверить, имеет ли список такой объект, то я бы предположил, что просто выполните:

return someList.Any(item => item.Id == cmpItem.Id);

Ответ 2

List<T> использует компаратор, возвращаемый EqualityComparer<T>.Default, и в соответствии с документацией для этого:

Свойство Default проверяет, тип T реализует System.IEquatable(Of T) и, если это так, возвращает EqualityComparer (Of T), который использует эту реализацию. В противном случае он возвращает EqualityComparer (Of T), который использует переопределения Object.Equals и Object.GetHashCode, предоставленный T.

Таким образом, вы можете либо реализовать IEquatable<T> в своем пользовательском классе, либо переопределить методы EqualsGetHashCode), чтобы выполнить сравнение по требуемым свойствам. В качестве альтернативы вы можете использовать linq:

bool contains = list.Any(i => i.Id == obj.Id);

Ответ 3

Вы можете использовать LINQ, чтобы сделать это довольно легко.

var result = MyCollection.Any(p=>p.myId == Id);
if(result)
{
     //something
}

Ответ 4

Вы можете переопределить Equals и GetHashCode, реализовать IEqualityComparer<MyObject> и использовать это в вызове Contains или использовать метод расширения, например Any

if (!myList.Any(obj => obj.Property == obj2.Property && obj.Property2 == obj2.Property2))
   myList.Add(obj2);

Ответ 5

Вы можете использовать IEquatable<T>. Реализуйте это в своем классе, а затем проверьте, имеет ли T, переданный в Equals, тот же идентификатор, что и this.Id. Я уверен, что это работает для проверки ключа в словаре, но я не использовал его для коллекции.

Ответ 6

Сначала определите вспомогательный класс с помощью IEqualityComparer.

public class MyEqualityComparer<T> : IEqualityComparer<T>
{
    Func<T, int> _hashDelegate;

    public MyEqualityComparer(Func<T, int> hashDelegate)
    {
        _hashDelegate = hashDelegate;
    }

    public bool Equals(T x, T y)
    {
        return _hashDelegate(x) == _hashDelegate(y);
    }

    public int GetHashCode(T obj)
    {
        return _hashDelegate(obj);
    }
}

Затем в вашем коде просто определите компаратор и используйте его:

var myComparer = new MyEqualityComparer<MyObject>(delegate(MyObject obj){
    return obj.ID;
});

var result = collection
   .Where(f => anotherCollection.Contains(f.First, myComparer))
   .ToArray();

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