.Contains () in un elenco di oggetti di classe personalizzati


95

Sto cercando di utilizzare la .Contains()funzione su un elenco di oggetti personalizzati

Questa è la lista:

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

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

Quindi cerco di trovare un prodotto simile nell'elenco:

if (CartProducts.Contains(p))

Ma ignora prodotti simili e non mi sembra di sapere cosa controlla: l'ID? o tutto?

Grazie in anticipo! :)

Risposte:


119

È necessario implementare IEquatableo sostituire Equals()eGetHashCode()

Per esempio:

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
ma dov'è GetHashCode()?
zionpi

1
Non è necessario implementare GetHashCode (). Funziona senza.
user890332

141

Se utilizzi .NET 3.5 o versioni successive, puoi utilizzare i metodi di estensione LINQ per ottenere un controllo "contiene" con il Anymetodo di estensione:

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

Questo verificherà l'esistenza di un prodotto all'interno del CartProductsquale ha un ID che corrisponde all'ID di p. È possibile inserire qualsiasi espressione booleana dopo =>per eseguire il controllo.

Questo ha anche il vantaggio di lavorare per le query LINQ-to-SQL e per le query in memoria, dove Containsno.


12

Verifica se l'oggetto specifico è contenuto nell'elenco.

Potrebbe essere meglio usare il metodo Trova nell'elenco.

Ecco un esempio

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

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

spero che aiuti

Dovresti anche guardare LinQ - forse eccessivo per questo, ma comunque uno strumento utile ...


1
come può Linq essere eccessivo?
Mel Gerats

@ MEL - Perché immischiarsi in una query e digitare inferenza per qualcosa di così semplice? Detto questo, potrebbe essere più leggibile a qualcuno che non ha familiarità con le lamda ...
Martin Milan

+1 Un buon esempio chiaro, che mostra l'opzione che non sarebbe influenzata da modifiche altrove (cioè se il Equals()metodo fosse cambiato per qualsiasi motivo)
Rowland Shaw

4

Per impostazione predefinita, i tipi di riferimento hanno l'uguaglianza dei riferimenti (ovvero due istanze sono uguali solo se sono lo stesso oggetto).

È necessario eseguire l'override Object.Equals(e la Object.GetHashCodecorrispondenza) per implementare la propria uguaglianza. (Ed è quindi buona pratica implementare un ==operatore di uguaglianza ,,.)


1
Perché eseguire l'override di Object.Equals, che potrebbe avere conseguenze in altre parti del codice? Per me, ha più senso modificare il codice di ricerca di conseguenza, e non la classe sottostante dell'oggetto ricercato ...
Martin Milan

Hai qualche esempio di questo, .Find () o sovrascrivendo Object.Equals / GetHashCode?
Jan Johansen

@Martin IT sarebbe molto rotto se volessi che il confronto di due CartProductoggetti si comportasse in modo diverso in luoghi diversi.
Rowland Shaw

1
@ Rowland - Ma non sto dicendo che avrebbe dovuto cambiare il modo in cui funziona un confronto. Se vuole un oggetto specifico, usa Contains (). Se vuole che qualsiasi oggetto corrisponda a un criterio specificato, usa Find () con un predicato adatto (espressione lamda) ... In realtà sto sostenendo che non tocchi A TUTTI il codice di confronto - chiami semplicemente il metodo giusto sul elenco per il compito che stai cercando di svolgere ...
Martin Milan

1
@ Martin sembra che ho interpretato male il tuo commento come qualcosa sulla falsariga di "override Contains()". Concordo sul fatto che Find()potrebbe risolvere il problema, anche se suggerirei che un metodo di uguaglianza adatto potrebbe essere più utile in molti altri casi, poiché l'OP non ha notato che i riferimenti per due istanze della stessa entità erano diversi.
Rowland Shaw

1

Devi creare un oggetto dalla tua lista come:

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

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

Quell'oggetto ottiene il valore cercato cercando in base alle sue proprietà: x.name

Quindi puoi usare metodi List come Contains o Remove

if (lst.Contains(obj))
{
   lst.Remove(obj);
}

0

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

}

Usato:

if (CartProducts.Contains(p))

-1

Se vuoi avere il controllo su questo, devi implementare l '[IEquatable interface] [1]

[1]: http: // Questo metodo determina l'uguaglianza utilizzando l'operatore di confronto di uguaglianza predefinito, come definito dall'implementazione dell'oggetto del metodo IEquatable.Equals per T (il tipo di valori nell'elenco).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.