Antnrmnd
Antnrmnd

Reputation: 48

C# List<myClass> Contains

Ok, so I have a List of type my own class, which in turn has parameters such as strings and integers, and I want to check inside my list with Contains() if I have a match with something a user would input.

As for the example you can assume there are already members in the list.

class Person 
{
    public string Name {get; set;}
    public int Age {get; set;}
    public int Id {get; set;}

    public Person()
    {
    }
}

class PersonList : Person
{
    List<Person> personList = new List<Person>();

    public bool Exist(int inputParameter)
    {
       if (personList.Contains(new Person { Id = inputParameter }))
       {
           return true;
       }
       else
       {
           return false;
       }
    }
}

Now even when I'm sure the input belongs to an already existing member of the list, my Exist method always returns false. Has anybody have any clue as to what I might not be doing right?

Upvotes: 0

Views: 2723

Answers (3)

Joel Coehoorn
Joel Coehoorn

Reputation: 416059

The .Contains() method uses the default equality comparer, which means it calls the .Equals() method for the type to find a match.

For reference types like your Person class, the default method inherited from Object uses reference equality, meaning it will only return true if they are the exact same object instance. If you want a different type of comparison, you should overload the Equals() method in the type (and implement IEquatable<T> and override GetHashCode() while you're at it).

public class Person : IEquatable<Person>
{
    public string Name {get; set;}
    public int Age {get; set;}
    public int Id {get; set;}

    public bool Equals(Person other)
    {
        return other is Object && this.Id == other.Id;
    }

    public override bool Equals(Object other)
    {
        if (other is Person) return Equals((Person)other);
        return false;
    }

    public override int GetHashCode()
    {   //naive implementation. This is adequate as long as you're **SURE** all instances will have a unique/correct `Id` value.
        return this.Id.GetHashCode();
    }
}

Going beyond this, I would not build a separate PersonList type. The List<Person> generic collection almost certainly already does the things you need.

That out of the way, it's still worthwhile to address how you might implement the Exist() method from the original PersonList class. One thing I would do here is avoid trying to allocate new objects to complete the search. With that in mind:

public bool Exist(int inputParameter)
{
    return personList.Any(p => p.Id == inputParameter);
}

Note, this will still currently allocate a new iterator object in most cases, but work is being done to make these linq operations more memory-friendly over time. It's also a whole lot less code. If you have a function that gives you a boolean result, there's no good reason to put it in an if() block just to return that same result.

And if we want to get really aggressive on the allocations, we can do it like this:

public bool Exist(int inputParameter)
{
    foreach(var p in personList)
    {
       if (p.Id == inputParameter) return true;
    }
    return false;
}

Upvotes: 3

Mohammed Sajid
Mohammed Sajid

Reputation: 4913

You can also use Any instead Contains, try to change the code of Exist method to:

public bool Exist(int inputParameter)
{
    return personList.Any(person => person.Id == inputParameter);
}

Upvotes: 3

Sean
Sean

Reputation: 62522

You can use Any

 public bool Exist(inputParameter)
    {
       if (personList.Any(person => person.Id == inputParameter))
       {
           return true;
       }
       else
       {
           return false;
       }
    }

Which you can collapse to just:

public bool Exist(inputParameter)
{
  return personList.Any(person => person.Id == inputParameter);
}

Upvotes: 1

Related Questions