.Contains () em uma lista de objetos de classe personalizados

95

Estou tentando usar a .Contains()função em uma lista de objetos personalizados

Esta é a lista:

List<CartProduct> CartProducts = new List<CartProduct>();

E o CartProduct:

public class CartProduct
{
    public Int32 ID;
    public String Name;
    public Int32 Number;
    public Decimal CurrentPrice;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="ID">The ID of the product</param>
    /// <param name="Name">The name of the product</param>
    /// <param name="Number">The total number of that product</param>
    /// <param name="CurrentPrice">The currentprice for the product (1 piece)</param>
    public CartProduct(Int32 ID, String Name, Int32 Number, Decimal CurrentPrice)
    {
        this.ID = ID;
        this.Name = Name;
        this.Number = Number;
        this.CurrentPrice = CurrentPrice;
    }
    public String ToString()
    {
        return Name;
    }
}

Então, tento encontrar um produto de carrinho semelhante na lista:

if (CartProducts.Contains(p))

Mas ele ignora produtos de carrinho semelhantes e eu não pareço saber o que ele verifica - o ID? ou tudo isso?

Desde já, obrigado! :)

Jan Johansen
fonte

Respostas:

119

Você precisa implementar IEquatableou substituir Equals()eGetHashCode()

Por exemplo:

public class CartProduct : IEquatable<CartProduct>
{
    public Int32 ID;
    public String Name;
    public Int32 Number;
    public Decimal CurrentPrice;

    public CartProduct(Int32 ID, String Name, Int32 Number, Decimal CurrentPrice)
    {
        this.ID = ID;
        this.Name = Name;
        this.Number = Number;
        this.CurrentPrice = CurrentPrice;
    }

    public String ToString()
    {
        return Name;
    }

    public bool Equals( CartProduct other )
    {
        // Would still want to check for null etc. first.
        return this.ID == other.ID && 
               this.Name == other.Name && 
               this.Number == other.Number && 
               this.CurrentPrice == other.CurrentPrice;
    }
}
Rowland Shaw
fonte
4
mas onde fica GetHashCode()?
zionpi
1
Você não precisa implementar GetHashCode (). Funciona sem ele.
user890332
141

Se estiver usando .NET 3.5 ou mais recente, você pode usar métodos de extensão LINQ para obter uma verificação "contém" com o Anymétodo de extensão:

if(CartProducts.Any(prod => prod.ID == p.ID))

Isso verificará a existência de um produto dentro do CartProductsqual tenha um ID correspondente ao ID de p. Você pode colocar qualquer expressão booleana após o =>para realizar a verificação.

Isso também tem a vantagem de trabalhar para consultas LINQ-to-SQL, bem como consultas na memória, onde Containsnão funciona.

Paul Turner
fonte
12

Ele verifica se o objeto específico está contido na lista.

Você pode usar o método Find da lista melhor.

Aqui está um exemplo

List<CartProduct> lst = new List<CartProduct>();

CartProduct objBeer;
objBeer = lst.Find(x => (x.Name == "Beer"));

espero que ajude

Você também deve olhar para o LinQ - um exagero para isso, talvez, mas uma ferramenta útil, no entanto ...

Martin Milan
fonte
1
como pode o Linq ser um exagero?
Mel Gerats
@MEL - Por que se confundir em uma consulta e inferência de tipo para algo tão simples? Dito isso, pode ser mais legível para alguém não familiarizado com lamdas ...
Martin Milan
+1 Bom exemplo claro, que mostra a opção que não seria afetada por mudanças em outro lugar (ou seja, se o Equals()método foi alterado por qualquer motivo)
Rowland Shaw
4

Por padrão, os tipos de referência têm igualdade de referência (ou seja, duas instâncias são iguais apenas se forem o mesmo objeto).

Você precisa substituir Object.Equals(e Object.GetHashCodecombinar) para implementar sua própria igualdade. (E, então, é uma boa prática implementar um ==operador de igualdade ,,.)

Richard
fonte
1
Por que substituir Object.Equals, o que poderia ter consequências em outras partes do código? Para mim, faz mais sentido alterar o código de pesquisa de acordo, e não a classe subjacente do objeto que está sendo pesquisado ...
Martin Milan
Você tem alguns exemplos disso, .Find () ou substituindo o Object.Equals / GetHashCode?
Jan Johansen
O @Martin IT ficaria muito mal se você quisesse que a comparação de dois CartProductobjetos se comportasse de maneira diferente em lugares diferentes.
Rowland Shaw
1
@Rowland - Mas não estou dizendo que ele teria que mudar o funcionamento de uma comparação. Se ele quiser um objeto específico, use Contains (). Se ele quiser que qualquer objeto corresponda a um critério especificado, use Find () com um predicado adequado (expressão lamda) ... Na verdade, estou argumentando que você não toca no código de comparação AT ALL - você apenas chama o método correto no lista para a tarefa que você está tentando realizar ...
Martin Milan
1
@Martin parece Eu interpretei mal o seu comentário como algo parecido com "substituir Contains()". Concordo que Find()poderia resolver o problema, embora eu sugerisse que um método de equals adequado pode ser mais útil em muitos outros casos, já que o OP não detectou que as referências para duas instâncias da mesma entidade eram diferentes.
Rowland Shaw
1

Você precisa criar um objeto de sua lista como:

List<CartProduct> lst = new List<CartProduct>();

CartProduct obj = lst.Find(x => (x.Name == "product name"));

Esse objeto obtém o valor procurado pesquisando por suas propriedades: x.name

Em seguida, você pode usar métodos List como Contains ou Remove

if (lst.Contains(obj))
{
   lst.Remove(obj);
}
José Chávez
fonte
0

Implementar override Equals()eGetHashCode()

public class CartProduct
{
    public Int32 ID;
    ...

    public CartProduct(Int32 ID, ...)
    {
        this.ID = ID;
        ...
    }

    public override int GetHashCode()
    {
        return ID;
    }

    public override bool Equals(Object obj)
        {
            if (obj == null || !(obj is CartProduct))
                return false;
            else
                return GetHashCode() == ((CartProduct)obj).GetHashCode();
        }

}

usava:

if (CartProducts.Contains(p))
A. Morel
fonte
-1

Se você quiser ter controle sobre isso, você precisa implementar a [interface IEquatable] [1]

[1]: http: // Este método determina a igualdade usando o comparador de igualdade padrão, conforme definido pela implementação do objeto do método IEquatable.Equals para T (o tipo de valores na lista).

Gerrie Schenck
fonte