.Contains () na liście niestandardowych obiektów klas


95

Próbuję użyć .Contains() funkcji na liście obiektów niestandardowych

Oto lista:

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

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

Więc staram się znaleźć podobny produkt w koszyku na liście:

if (CartProducts.Contains(p))

Ale ignoruje podobne produkty w koszyku i wydaje mi się, że nie wiem, co sprawdza - identyfikator? czy to wszystko?

Z góry dziękuję! :)

Odpowiedzi:


119

Musisz zaimplementować IEquatablelub zastąpić Equals()iGetHashCode()

Na przykład:

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
ale gdzie jest GetHashCode()?
zionpi

1
Nie musisz implementować GetHashCode (). Działa bez tego.
user890332

141

Jeśli używasz .NET 3.5 lub nowszego, możesz użyć metod rozszerzenia LINQ, aby uzyskać sprawdzenie „zawiera” za pomocą Anymetody rozszerzenia:

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

Spowoduje to sprawdzenie, czy istnieje produkt, w ramach CartProductsktórego identyfikator jest zgodny z identyfikatorem p. =>Aby wykonać sprawdzenie, po znaku można umieścić dowolne wyrażenie logiczne .

Ma to również tę zaletę, że działa z zapytaniami LINQ-to-SQL, a także z zapytaniami w pamięci, gdzie Containsnie.


12

Sprawdza, czy określony obiekt znajduje się na liście.

Możesz lepiej użyć metody Find na liście.

Oto przykład

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

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

Mam nadzieję, że to pomoże

Powinieneś także spojrzeć na LinQ - być może przesada, ale mimo to przydatne narzędzie ...


1
jak Linq może kiedykolwiek być przesadą?
Mel Gerats

@MEL - Po co mieszać się w zapytaniu i wpisywać wnioskowanie dla czegoś tak prostego? To powiedziawszy, może być bardziej czytelne dla kogoś, kto nie jest zaznajomiony z lamdami ...
Martin Milan

+1 Dobry, jasny przykład, który pokazuje opcję, na którą nie miałyby wpływu zmiany w innym miejscu (tj. Gdyby Equals()metoda została zmieniona z jakiegokolwiek powodu)
Rowland Shaw

4

Domyślnie typy odwołań mają równość odwołań (tj. Dwa wystąpienia są równe tylko wtedy, gdy są tym samym obiektem).

Musisz nadpisać Object.Equals(i Object.GetHashCodedopasować), aby zaimplementować własną równość. (A zatem dobrą praktyką jest wdrożenie ==operatora równości ,,).


1
Po co zastępować Object.Equals, co może mieć konsekwencje w innym miejscu kodu? Dla mnie bardziej sensowne jest odpowiednie zmodyfikowanie kodu wyszukiwania, a nie podstawowej klasy obiektu przeszukiwanego ...
Martin Milan

Czy masz jakieś przykłady tego, .Find () lub przesłanianie Object.Equals / GetHashCode?
Jan Johansen

@Martin IT byłoby bardzo zepsute, gdybyś chciał, aby porównanie dwóch CartProductobiektów zachowywało się inaczej w różnych miejscach.
Rowland Shaw

1
@Rowland - Ale nie mówię, że musiałby zmieniać sposób działania porównania. Jeśli chce konkretnego obiektu, użyj Contains (). Jeśli chce jakikolwiek obiekt spełniający określone kryteria, użyj funkcji Find () z odpowiednim predykatem (wyrażeniem lamda) ... Właściwie twierdzę, że w ogóle nie dotykasz kodu porównania - po prostu wywołujesz odpowiednią metodę na lista zadań, które próbujesz wykonać ...
Martin Milan

1
@Martin wygląda na to, że błędnie zinterpretowałem Twój komentarz jako coś w rodzaju „zastąpienia Contains()”. Zgadzam się, że Find()mogłoby to rozwiązać problem, chociaż sugerowałbym, że posiadanie odpowiedniej metody równości może być bardziej przydatne w wielu innych przypadkach, ponieważ PO nie zauważył, że odniesienia dla dwóch instancji tego samego podmiotu były różne.
Rowland Shaw

1

Musisz utworzyć obiekt ze swojej listy, taki jak:

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

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

Ten obiekt uzyskuje wyglądaną wartość wyszukując po ich właściwościach: x.nazwa

Następnie możesz użyć metod listy, takich jak Contains lub Remove

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

0

Wdrożenie override Equals()iGetHashCode()

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

}

używany:

if (CartProducts.Contains(p))

-1

Jeśli chcesz mieć nad tym kontrolę, musisz zaimplementować [interfejs IEquatable] [1]

[1]: http: // Ta metoda określa równość przy użyciu domyślnej funkcji porównującej równość, zgodnie z definicją w implementacji metody IEquatable.Equals obiektu dla T (typ wartości na liście).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.