Что использует Collection.Contains() для проверки существующих объектов?
У меня есть строго типизированный список пользовательских объектов MyObject, у которого есть идентификатор свойства вместе с некоторыми другими свойствами.
Скажем, что Id из MyObject определяет его как уникальное, и я хочу проверить, не имеет ли моя коллекция еще объекта MyObject, который имеет идентификатор 1, прежде чем я добавлю новый MyObject в коллекцию.
Я хочу использовать if (! List.Contains(myObj)), но как я могу применить тот факт, что только одно или два свойства MyObject определяют его как уникальное?
Я могу использовать IComparable? Или мне нужно только переопределить метод Equals, но мне нужно сначала наследовать что-то в этом роде?
Спасибо
Ответы
Ответ 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>
в своем пользовательском классе, либо переопределить методы Equals
(и GetHashCode
), чтобы выполнить сравнение по требуемым свойствам. В качестве альтернативы вы можете использовать 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 без изменения ваших классов. Вы также можете использовать его для обработки объекта из сторонних библиотек, поскольку вы не можете изменять их код.