.Contains () en una lista de objetos de clase personalizados

95

Estoy tratando de usar la .Contains()función en una lista de objetos personalizados.

Esta es la lista:

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

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

Así que trato de encontrar un producto de carrito similar dentro de la lista:

if (CartProducts.Contains(p))

Pero ignora productos de carro similares y no parece saber qué verifica: ¿la identificación? o todo eso?

¡Gracias por adelantado! :)

Jan Johansen
fuente

Respuestas:

119

Necesita implementar IEquatableo anular Equals()yGetHashCode()

Por ejemplo:

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
fuente
4
pero ¿dónde está GetHashCode()?
zionpi
1
No es necesario implementar GetHashCode (). Funciona sin él.
user890332
141

Si está usando .NET 3.5 o más reciente, puede usar los métodos de extensión LINQ para lograr una verificación de "contiene" con el Anymétodo de extensión:

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

Esto verificará la existencia de un producto dentro del CartProductscual tenga un ID que coincida con el ID de p. Puede poner cualquier expresión booleana después de la =>para realizar la comprobación.

Esto también tiene la ventaja de funcionar para consultas LINQ-to-SQL, así como consultas en memoria, donde Containsno lo hace.

Paul Turner
fuente
12

Comprueba si el objeto específico está incluido en la lista.

Es posible que sea mejor utilizar el método Buscar en la lista.

Aquí hay un ejemplo

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

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

Espero que ayude

También debería mirar LinQ - exagerado para esto quizás, pero una herramienta útil no obstante ...

Martín Milán
fuente
1
¿Cómo puede Linq ser exagerado?
Mel Gerats
@MEL - ¿Por qué mezclarse en una consulta y escribir inferencia para algo tan simple? Dicho esto, sin embargo, podría ser más legible para alguien que no esté familiarizado con las lamdas ...
Martin Milan
+1 Buen ejemplo claro, que muestra la opción que no se vería afectada por cambios en otros lugares (es decir, si el Equals()método se cambia por cualquier motivo)
Rowland Shaw
4

Por defecto, los tipos de referencia tienen igualdad de referencia (es decir, dos instancias solo son iguales si son el mismo objeto).

Debe anular Object.Equals(y Object.GetHashCodehacer coincidir) para implementar su propia igualdad. (Y es una buena práctica implementar un ==operador de igualdad ,,).

Ricardo
fuente
1
¿Por qué anular Object.Equals, que podría tener consecuencias en otras partes del código? Para mí, tiene más sentido modificar el código de búsqueda en consecuencia, y no la clase subyacente de objeto que se busca ...
Martin Milan
¿Tiene algunos ejemplos de esto, .Find () o anulando Object.Equals / GetHashCode?
Jan Johansen
@Martin IT estaría muy roto si quisiera que la comparación de dos CartProductobjetos se comporte de manera diferente en diferentes lugares.
Rowland Shaw
1
@ Rowland - Pero no estoy diciendo que tenga que cambiar cómo funciona una comparación. Si quiere un objeto específico, use Contains (). Si quiere cualquier objeto que coincida con un criterio específico, use Find () con un predicado adecuado (expresión lamda) ... En realidad, estoy argumentando que no toca el código de comparación EN NINGÚN TIPO, simplemente llame al método correcto en el lista de la tarea que está tratando de lograr ...
Martin Milan
1
@Martin Parece que malinterpreté tu comentario como algo parecido a "anular Contains()". Find()Estoy de acuerdo en que podría resolver el problema, aunque sugeriría que tener un método igual adecuado puede ser más útil en muchos otros casos, ya que el OP no detectó que las referencias para dos instancias de la misma entidad eran diferentes.
Rowland Shaw
1

Necesita crear un objeto de su lista como:

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

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

Ese objeto obtiene el valor buscado buscando por sus propiedades: x.name

Luego puede usar métodos de lista como Contiene o Eliminar

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

Implementar override Equals()yGetHashCode()

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

}

usado:

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

Si desea tener control sobre esto, debe implementar la [interfaz IEquatable] [1]

[1]: http: // Este método determina la igualdad utilizando el comparador de igualdad predeterminado, según lo definido por la implementación del objeto del método IEquatable.Equals para T (el tipo de valores en la lista).

Gerrie Schenck
fuente