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


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.Equals(і Object.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.