.Contains () ในรายการของคลาสออบเจ็กต์แบบกำหนดเอง


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))

แต่มันไม่สนใจผลิตภัณฑ์ในรถเข็นที่คล้ายกันและฉันไม่รู้ว่ามันตรวจสอบอะไร - ID? หรือทั้งหมด?

ขอบคุณล่วงหน้า! :)

คำตอบ:


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 จะ overkill ได้อย่างไร?
Mel Gerats

@MEL - ทำไมต้องผสมกันในแบบสอบถามและพิมพ์การอนุมานสำหรับสิ่งที่เรียบง่ายนี้? ที่กล่าวว่ามันอาจจะอ่านได้มากกว่าสำหรับคนที่ไม่คุ้นเคยกับ lamdas ...
Martin Milan

+1 ตัวอย่างที่ชัดเจนที่แสดงให้เห็นตัวเลือกที่จะไม่ได้รับผลกระทบจากการเปลี่ยนแปลงที่อื่น (เช่นหากEquals()วิธีการเปลี่ยนแปลงไม่ว่าด้วยเหตุผลใดก็ตาม)
Rowland Shaw

4

โดยค่าเริ่มต้นประเภทการอ้างอิงจะมีความเท่าเทียมกันในการอ้างอิง (เช่นสองอินสแตนซ์จะเท่ากันก็ต่อเมื่อเป็นวัตถุเดียวกัน)

คุณต้องลบล้างObject.Equals(และObject.GetHashCodeจับคู่) เพื่อใช้ความเท่าเทียมกันของคุณเอง (และเป็นแนวทางปฏิบัติที่ดีในการใช้ความเท่าเทียมกัน==ตัวดำเนินการ)


1
เหตุใดจึงแทนที่ Object.Equals ซึ่งอาจมีผลกระทบที่อื่นในโค้ด สำหรับฉันมันสมเหตุสมผลกว่าที่จะแก้ไขโค้ดการค้นหาให้เหมาะสมและไม่ใช่คลาสพื้นฐานของอ็อบเจ็กต์ที่ถูกค้นหา ...
Martin Milan

คุณยกตัวอย่างบางส่วนของสิ่งนี้, .Find () หรือการแทนที่ Object.Equals / GetHashCode หรือไม่?
Jan Johansen

@Martin IT จะพังมากถ้าคุณต้องการให้การเปรียบเทียบของสองCartProductวัตถุทำงานแตกต่างกันในสถานที่ต่างๆ
Rowland Shaw

1
@Rowland - แต่ฉันไม่ได้บอกว่าเขาจะต้องเปลี่ยนวิธีการทำงานของการเปรียบเทียบ ถ้าเขาต้องการวัตถุเฉพาะให้ใช้มี () หากเขาต้องการวัตถุใด ๆ ที่ตรงกับเกณฑ์ที่ระบุให้ใช้ Find () กับเพรดิเคตที่เหมาะสม (นิพจน์ lamda) ... จริงๆแล้วฉันเถียงว่าคุณไม่ได้แตะรหัสเปรียบเทียบเลย - คุณแค่เรียกวิธีการที่ถูกต้องบน รายการสำหรับงานที่คุณพยายามทำให้สำเร็จ ...
Martin Milan

1
@Martin ปรากฏว่าฉันตีความความคิดเห็นของคุณผิดว่าเป็นข้อความ "ลบล้างContains()" ยอมรับว่าFind()สามารถแก้ปัญหาได้แม้ว่าฉันจะแนะนำให้ใช้วิธีการเท่ากับที่เหมาะสมอาจมีประโยชน์มากกว่าในกรณีอื่น ๆ เนื่องจาก OP ไม่ได้ระบุว่าการอ้างอิงสำหรับสองอินสแตนซ์ของเอนทิตีเดียวกันแตกต่างกัน
Rowland Shaw

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 (ประเภทของค่าในรายการ)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.