views:

152

answers:

5

Hello,

I'm trying to use the .Contains function on a list of custom objects

This is the list:

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

And the 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;
    }
}

So i try to find a similar cartproduct within the list:

if (CartProducts.Contains(p))

But it ignores similar cartproducts and i don't seem to know what it checks on - the ID? or it all?

Thanks in advance! :)

+4  A: 

By default reference types have reference equality (i.e. two instances are only equal if they are the same object).

You need to override Object.Equals (and Object.GetHashCode to match) to implement your own equality. (And it is then good practice to implement an equality, ==, operator.)

Richard
Why override Object.Equals, which could have consequences elsewhere in the code?To me, it makes more sense to amend the search code accordingly, and not the underlying class of object being searched upon...
Martin Milan
Do you hvave some examples of this, .Find() or overriding the Object.Equals/GetHashCode?
Buckley
@Martin IT would be very broken if you wanted the comparison of two `CartProduct` objects to behave differently in different places.
Rowland Shaw
@Martin: Yes, it will be used whenever something tries to compare instances of your type. (If you want just a local effect use `List<T>.Exists()` passing in a method that does the comparison.)
Richard
@Buckley: RTFM: http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx
Richard
@Rowland - But I'm not saying he would have to change how a comparison works. If he wants a specific object, use Contains(). If he wants any object matching a specified criteria, use Find() with a suitable predicate (lamda expression)... I'm actually arguing that you don't touch the comparison code AT ALL - you just call the right method on the list for the task you're trying to accomplish...
Martin Milan
@Richard - Exists() just tells you that there is a suitable object there. If you want to return that object, you'll need Find() - with a suitable predicate as you have suggested.
Martin Milan
@Martin Appears I misinterpreted your comment to be something along the lines of "override `Contains()`". Agree that `Find()` could solve the issue, although I would suggest having a suitable equals method may be more useful in loads of other cases, as the OP didn't spot that the references for two instances of the same entity were different.
Rowland Shaw
See my edited answer...
Martin Milan
@Martin: `List.Contains` determines existence using an object, `List.Exists` determines the same thing with a predicate.
Richard
@Rowland It's horses for courses - but I would be reluctant to make such a fundamental change to a class of objects just to enable searching like this. You're right, it's one way of doing it - just not the way I would have gone myself...
Martin Milan
@Richard - True - but I think the original poster wants to actually retrieve the object, not merely test if it exists...
Martin Milan
@Richard - Actually - I see where you're coming from now. Either one of us could be right lol...
Martin Milan
A: 

If you want to have control over this you need to implement the [IEquatable interface][1]

[1]: http://This method determines equality by using the default equality comparer, as defined by the object's implementation of the IEquatable.Equals method for T (the type of values in the list).

Gerrie Schenck
+3  A: 

You need to implement IEquatable or override Equals() and GetHashCode()

For example:

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;
    }
}
Rowland Shaw
Thanks Rowland :)
Buckley
+1  A: 

It checks to see whether the specific object is contained in the list.

You might be better using the Find method on the list.

Here's an example

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

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

Hope that helps

You should also look at LinQ - overkill for this perhaps, but a useful tool nonetheless...

Martin Milan
how can Linq ever be overkill?
Mel Gerats
@MEL - Why get mixed up in a query and type inference for something this simple? That said though, it might be more readable to someone not familiar with lamdas...
Martin Milan
+1 Good clear example, that shows the option that wouldn't be affected by changes elsewhere (i.e. if the `Equals()` method got changed for whatever reason)
Rowland Shaw
+3  A: 

If you are using .NET 3.5 you can use LINQ extension methods to achieve a "contains" check with the Any extension method:

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

This will check for the existence of a product within CartProducts which has an ID matching the ID of p. You can put any boolean expression after the => to perform the check on.

Programming Hero