.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! :)

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

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.


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 ...


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 ,,.)


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

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))

-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).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.