46

I'm trying to use a List<T> with a custom class of mine, and being able to use methods like Contains(), Find(), etc., on the list. I thought I'd just have to overload the operator == but apparently, one way of doing that is to use a delegate method with the Find()...

Note: Right now, I've overloaded the Equals() method to get the Contains() method to work, but I still couldn't get the Find() function to work.

What would be the best way of getting both to work?

I'm using the latest C# /.NET framework version with mono, on linux.

edit: Here's my code

using System;
namespace GuerreDesClans
{
public class Reponse : IEquatable<Reponse>
{
    public Reponse ()
    {
        m_statement = string.Empty;
        m_pointage = 0;
    }

    public Reponse (string statement, int pointage)
    {
        m_pointage = pointage;
        m_statement = statement;
    }


    /*
     * attributs privés
     */

    private string m_statement;
    private int m_pointage;


    /*
     * properties
     */

    public string Statement {
        get { return m_statement; }
        set { m_statement = value; }
    }

    public int Pointage {
        get { return m_pointage; }
        set { m_pointage = value; }
    }

    /*
     * Equatable
     */

    public bool Equals (Reponse other)
    {
        if (this.m_statement == other.m_statement)
            return true;
        else
            return false;
    }
}

}

and how I would like to search my Reponse objects using the find() function...

list.find("statement1"); // would return a Reponse object
Pacane
  • 20,273
  • 18
  • 60
  • 97

5 Answers5

73

Find() will find the element that matches the predicate that you pass as a parameter, so it is not related to Equals() or the == operator.

var element = myList.Find(e => [some condition on e]);

In this case, I have used a lambda expression as a predicate. You might want to read on this. In the case of Find(), your expression should take an element and return a bool.

In your case, that would be:

var reponse = list.Find(r => r.Statement == "statement1")

And to answer the question in the comments, this is the equivalent in .NET 2.0, before lambda expressions were introduced:

var response = list.Find(delegate (Response r) {
    return r.Statement == "statement1";
});
Xavier Poinas
  • 19,377
  • 14
  • 63
  • 95
  • 1
    Can you provide a .NET 2.0 example? I'm in Unity3D which is stuck in .net 2.0 land – gman Nov 25 '14 at 03:30
  • Is it ok to think that the returned element will be a reference and that any modifications to it will be reflected on that same element contained in the list? – Hugo Allexis Cardona Mar 15 '17 at 14:31
  • @HugoAllexisCardona If the type of the element is a reference type, then yes. If it is a value type, then no. See https://msdn.microsoft.com/en-us/library/t63sy5hs.aspx. – Xavier Poinas Mar 16 '17 at 04:10
  • And how to deal if the element is not found? – Olivier Pons Nov 04 '17 at 09:18
  • @OlivierPons If the list contains reference types, Find will return null if the element is not found. If the list contains value types, it will return the default value for that type if the element is not found. In that case, there is no way to know if the element was found or not, unless the default value cannot match the predicate. – Xavier Poinas Nov 06 '17 at 08:47
46

You can use find with a Predicate as follows:

list.Find(x => x.Id == IdToFind);

This will return the first object in the list which meets the conditions defined by the predicate (ie in my example I am looking for an object with an ID).

Greg Sansom
  • 20,442
  • 6
  • 58
  • 76
8

Previous answers don't account for the fact that you've overloaded the equals operator and are using that to test for the sought element. In that case, your code would look like this:

list.Find(x => x == objectToFind);

Or, if you don't like lambda syntax, and have overriden object.Equals(object) or have implemented IEquatable<T>, you could do this:

list.Find(objectToFind.Equals);
phoog
  • 42,068
  • 6
  • 79
  • 117
  • These statements are both redundant because we already have a reference to objectToFind. The point of Find() is to locate an object we don't have a reference to. It's much easier, more logical and readable to use list.Contains(objectToFind). – Greg Sansom Dec 21 '10 at 22:28
  • 1
    @Greg Sansom: Of course. But the OP specifically said that he has the Contains method working, but also wants to use Find. Since he has overridden Equals to compare m_statement and ignore the value of m_pointage, the Find method would not necessarily return the same instance that is passed to it. The behavior of the Equals override may be questionable, but given that behavior, `list.Find(obj.Equals)` is not redundant. – phoog Dec 21 '10 at 22:49
  • Whats the return value if no item is found? – mrid Jul 27 '22 at 07:58
  • @mrid https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.find look in the "Returns" section. – phoog Jul 27 '22 at 09:56
0

http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx

        // Find a book by its ID.
        Book result = Books.Find(
        delegate(Book bk)
        {
            return bk.ID == IDtoFind;
        }
        );
        if (result != null)
        {
            DisplayResult(result, "Find by ID: " + IDtoFind);   
        }
        else
        {
            Console.WriteLine("\nNot found: {0}", IDtoFind);
        }
Shimon Doodkin
  • 4,310
  • 34
  • 37
0

It's easy, just use list.Find(x => x.name == "stringNameOfObjectToFind");

Junaid Pathan
  • 3,850
  • 1
  • 25
  • 47