.Містить () у списку нестандартних об'єктів класу


95

Я намагаюся використовувати .Contains()функцію у списку нестандартних об'єктів

Ось список:

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

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

Тому я намагаюся знайти подібний товар у списку:

if (CartProducts.Contains(p))

Але він ігнорує подібні продукти кошика, і я, здається, не знаю, що він перевіряє - ідентифікатор? чи все це?

Спасибі заздалегідь! :)

Відповіді:


119

Вам потрібно застосувати IEquatableабо замінити Equals()іGetHashCode()

Наприклад:

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
але де GetHashCode()?
zionpi

1
Вам не потрібно реалізовувати GetHashCode (). Це працює без цього.
user890332

141

Якщо ви використовуєте .NET 3.5 або новішу версію, ви можете використовувати методи розширення LINQ, щоб досягти перевірки "містить" за допомогою Anyметоду розширення:

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

Це перевірить наявність товару, в CartProductsякому є ідентифікатор, що відповідає ідентифікатору p. Ви можете поставити будь-який логічний вираз після, =>щоб виконати перевірку.

Це також має перевагу роботи для запитів LINQ-to-SQL, а також запитів в пам'яті, де Containsні.


12

Він перевіряє, чи не міститься конкретний об’єкт у списку.

Можливо, вам краще скористатися методом пошуку у списку.

Ось приклад

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

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

Сподіваюся, це допомагає

Ви також повинні подивитися на LinQ - це, можливо, надмірне, але тим не менш корисний інструмент ...


1
як Linq може колись переборщити?
Mel Gerats,

@MEL - Навіщо мішатись у запиті та наводити умовивід для чогось такого простого? Тим не менш, це може бути більш читабельним для когось, хто не знайомий з ламдами ...
Мартін Мілан

+1 Хороший наочний приклад, який показує варіант, на який не вплинуть зміни в інших місцях (тобто, якщо Equals()метод буде змінено з будь-якої причини)
Роуленд Шоу

4

За замовчуванням типи посилань мають посилальну рівність (тобто два екземпляри рівні, лише якщо це один і той же об'єкт).

Вам потрібно перевизначити Object.EqualsObject.GetHashCodeвідповідати), щоб реалізувати власну рівність. (І тоді хорошою практикою є впровадження рівності,, ==операторі.)


1
Чому перевизначати Object.Equals, що може мати наслідки деінде в коді? Для мене має більший сенс відповідно вносити зміни до коду пошуку, а не до базового класу об’єкта, який шукають ...
Мартін Мілан

Чи є у вас кілька прикладів цього. .Find () або перевизначення Object.Equals / GetHashCode?
Ян Йогансен

@Martin ІТ було б дуже зламаним, якби ви хотіли, щоб порівняння двох CartProductоб'єктів поводилося по-різному в різних місцях.
Роуленд Шоу

1
@Rowland - Але я не кажу, що йому довелося б змінити спосіб порівняння. Якщо він хоче конкретний об’єкт, використовуйте Contains (). Якщо він хоче будь-який об'єкт, що відповідає заданим критеріям, використовуйте Find () з відповідним предикатом (вираз lamda) ... Я насправді стверджую, що ви взагалі не торкаєтеся коду порівняння - ви просто викликаєте правильний метод на список завдання, яке ви намагаєтеся виконати ...
Мартін Мілан

1
@Martin Здається, я неправильно витлумачив ваш коментар як щось на зразок "перевизначити Contains()". Погодьтеся, що це Find()може вирішити проблему, хоча я б запропонував мати відповідний метод рівних може бути кориснішим у багатьох інших випадках, оскільки ОП не помітив, що посилання на два екземпляри одного і того ж об'єкта були різними.
Роуленд Шоу

1

Вам потрібно створити об’єкт зі списку, наприклад:

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

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

Цей об’єкт отримує шукане значення, здійснюючи пошук за їх властивостями: x.name

Тоді ви можете скористатися методами Списку, такими як Зміст або Видалення

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

0

Впровадити override Equals()іGetHashCode()

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

}

використовується:

if (CartProducts.Contains(p))

-1

Якщо ви хочете мати контроль над цим, вам потрібно застосувати [IEquatable інтерфейс] [1]

[1]: http: // Цей метод визначає рівність за допомогою порівняння рівності за замовчуванням, як визначено реалізацією об'єктом методу IEquatable.Equals для T (тип значень у списку).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.