Proper Use of .Contains() on a List of Custom Class Objects in C#

Dec 04, 2025 · Programming · 10 views · 7.8

Keywords: C# | List | Contains | Custom Class | IEquatable

Abstract: This article explains why the .Contains() method fails when used on a list of custom class objects in C# and provides a solution by implementing the IEquatable interface or overriding Equals() and GetHashCode(). It also discusses alternative approaches using LINQ to handle object existence checks efficiently.

Introduction

In C#, when working with lists of custom objects, the .Contains() method often yields unexpected results due to its default behavior. For instance, with a List<CartProduct>, checking for object presence may fail because .Contains() relies on reference equality rather than value-based comparison.

Default Behavior of .Contains()

The .Contains() method uses the object's Equals() implementation. For reference types like custom classes, the default Object.Equals() compares memory addresses, not property values. This means that even if two CartProduct objects share identical ID, name, and other attributes, .Contains() returns false if they are different instances.

Implementing Custom Equality

To make .Contains() work correctly, implement value equality in the class. The recommended approach is to use the IEquatable<T> interface and override Equals() and GetHashCode(). Here is an example based on the CartProduct class:

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 bool Equals(CartProduct other)
    {
        if (other == null) return false;
        return this.ID == other.ID && 
               this.Name == other.Name && 
               this.Number == other.Number && 
               this.CurrentPrice == other.CurrentPrice;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as CartProduct);
    }

    public override int GetHashCode()
    {
        return ID.GetHashCode();
    }
}

This implementation ensures that .Contains() compares objects based on property values, such as returning true when IDs match. Note that GetHashCode() should provide a consistent hash for better performance.

Alternative Approach Using LINQ

As a supplementary method, LINQ's Any() extension can be used for conditional checks. For example:

if (CartProducts.Any(p => p.ID == otherProduct.ID))
{
    // Handle existing product
}

This method offers flexibility without modifying class behavior, suitable for ad-hoc queries. However, implementing IEquatable aligns better with object-oriented design, enhancing code maintainability.

Conclusion

In C#, proper usage of .Contains() on lists of custom classes requires implementing equality comparison. By adopting IEquatable<T> or overriding methods, you ensure value-based logic and avoid pitfalls of reference equality. This is key to solving the issue and adhering to best programming practices.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.