views:

143

answers:

2

Hi guys

I was wandering how can I find out if an object already exists in my List. I'm adding "newPerson" (instance of Person class) in a List, but checking if newPerson contents/properties exists or not in the List.

This piece works fine:

        List<Person> people = this.GetPeople();
        if (people.Find(p => p.PersonID  == newPerson.PersonID
                    && p.PersonName  == newPerson.PersonName) != null)
        {
            MessageBox.Show("This person is already in the party!");
            return;
        }

First of all, I wanted to simplify/optimize this ugly code above. So I thought about using Contains method.

        List<Person> people = this.GetPeople();
        if (people.Contains<Person>(newPerson)) //it doesn't work!
        {
            MessageBox.Show("This person is already in the party!");
            return;
        }

The second code above doesn't work, I think it's comparing objects references and not object contents / properties.

Someone here on Stackoverflow and in link text was talking about using an class that implements IEqualityComparer. I gave it a try, but the code is much bigger now! Something like:

    public class PersonComparer : IEqualityComparer<Person>
    {
    // Products are equal if their names and i numbers are equal.
    public bool Equals(Person x, Person y)
    {

        // Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) return true;

        // Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        // Check whether the products' properties are equal.
        return x.PersonID == y.PersonID && x.PersonName == y. PersonName;
    }

    // If Equals() returns true for a pair of objects,
    // GetHashCode must return the same value for these objects.

    public int GetHashCode(Person p)
    {
        // Check whether the object is null.
        if (Object.ReferenceEquals(p, null)) return 0;

        // Get the hash code for the Name field if it is not null.
        int hashPersonName = p.PersonName == null ? 0 : p.PersonName.GetHashCode();
        int hashPersonID = i.PersonID.GetHashCode();

        // Calculate the hash code for the i.
        return hashPersonName ^ hashPersonID;
    }

}

and to use this comparer:

        PersonComparer comparer = new PersonComparer();
        if (people.Contains<Person>(newPerson, comparer))
        {
            MessageBox.Show("This person is already in the party.");
            return;
        }

Is there a smaller way to find my object's properties in a List?

+1  A: 

Use Exists or Any with a predicate:

List<Person> people = this.GetPeople();
if (people.Exists(p => p.PersonID  == newPerson.PersonID
                       && p.PersonName  == newPerson.PersonName))
{  
    MessageBox.Show("This person is already in the party!");
    return;
}

That will work with .NET 2.0 (and can be converted to C# 2 using an anonymous method). The more LINQy solution is Any:

List<Person> people = this.GetPeople();
if (people.Any(p => p.PersonID  == newPerson.PersonID
                    && p.PersonName  == newPerson.PersonName))
{
    MessageBox.Show("This person is already in the party!");
    return;
}
Jon Skeet
Yes I'll give it a try! Thank you Jon!
Junior Mayhé
+3  A: 

It sounds like your Person class should implement IEquatable<Person>. Yes, it is (a bit) more code, but then you don't have to repeat it each time you want to compare 2 person objects.

The Contains method of the list uses the Equals method of the object by default. So if you implement IEquatable correctly, you do not have to pass a custom IEqualityComparer.

driis