Что Collection.Contains () использует для проверки существующих объектов? - PullRequest
45 голосов
/ 03 сентября 2010

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



Спасибо

Ответы [ 6 ]

47 голосов
/ 03 сентября 2010

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);
28 голосов
/ 03 сентября 2010

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

Свойство Default проверяет, реализует ли тип T System.IEquatable (Интерфейса 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);
5 голосов
/ 03 сентября 2010

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

var result = MyCollection.Any(p=>p.myId == Id);
if(result)
{
     //something
}
2 голосов
/ 03 сентября 2010

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

if (!myList.Any(obj => obj.Property == obj2.Property && obj.Property2 == obj2.Property2))
   myList.Add(obj2);
0 голосов
/ 20 февраля 2017

Сначала определите вспомогательный класс с 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();

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

0 голосов
/ 03 сентября 2010

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

...