ti-enxame.com

O que Collection.Contains () usa para verificar objetos existentes?

Eu tenho uma lista fortemente digitada de objetos personalizados, MyObject, que possui um ID de propriedade junto com algumas outras propriedades.
Digamos que o ID de um MyObject o define como único e desejo verificar se minha coleção ainda não possui um objeto MyObject com um ID 1 antes de adicionar meu novo MyObject à coleção.
Desejo usar if (! List.Contains (myObj)), mas como impor o fato de que apenas uma ou duas propriedades do MyObject o definem como exclusivo?
Posso usar IComparable? Ou só preciso substituir um método Equals, mas preciso herdar algo primeiro, está certo?



Obrigado

47
topwik

List<T>.Contains Usa EqualityComparer<T>.Default, Que por sua vez usa IEquatable<T> Se o tipo implementá-lo, ou object.Equals Caso contrário.

Você pode simplesmente implementar IEquatable<T>, Mas é uma boa idéia substituir object.Equals Se você fizer isso, e uma muito boa idéia para substituir GetHashCode() if faça isso:

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

Observe que o código hash se refere aos critérios de igualdade. Isso é vital.

Isso também o torna aplicável a qualquer outro caso em que a igualdade, conforme definida pelo mesmo ID, seja útil. Se você tem um requisito para verificar se uma lista tem esse objeto, provavelmente sugeriria apenas:

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

List<T> usa o comparador retornado por EqualityComparer<T>.Default e de acordo com a documentação para isso:

A propriedade Default verifica se o tipo T implementa a interface System.IEquatable (Of T) e, nesse caso, retorna um EqualityComparer (Of T) que usa essa implementação. Caso contrário, ele retornará um EqualityComparer (Of T) que usa as substituições de Object.Equals e Object.GetHashCode fornecidas por T.

Então você pode implementar IEquatable<T> na sua classe personalizada ou substitua os métodos Equals (e GetHashCode) para fazer a comparação pelas propriedades necessárias. Como alternativa, você pode usar o linq:

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

Você pode usar o LINQ para fazer isso facilmente.

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

Você pode substituir Equals e GetHashCode, implementar um IEqualityComparer<MyObject> e use isso na chamada Contains, ou use um método de extensão como Any

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

Você pode usar IEquatable<T>. Implemente isso em sua classe e verifique se o T passado para o Equals tem o mesmo ID que this.Id. Tenho certeza que isso funciona para verificar uma chave em um dicionário, mas não a usei para uma coleção.

0
davisoa

Primeiro defina a classe auxiliar com 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);
    }
}

Em seguida, no seu código, apenas defina o comparador e use-o:

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

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

Dessa forma, você pode definir como o Equality é calculado sem modificar suas classes. Você também pode usá-lo para processar objetos de bibliotecas de terceiros, pois não pode modificar o código deles.

0
Tomas Kubes