Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C# Tips – Using delegate in List.Find() Predicate

0.00/5 (No votes)
20 May 2012 1  
How to use delegate in List.Find() predicate in C#

If we had a funcional language (eg or ), we could easily manage a collection or list.
With the , we can work equally functionally with (Exploring). using this feature of the we can develop, process and manage our data more easily, especially with .

An example that I wish to use, and is also the most frequent that I happened to develop, is the use of these anonymous delegates to the search function of a generic list ().

Instead of writing code with foreach loops every time I need to find an element in a set, I use a predicate that does the job in my place, so I can keep the code cleaner and I can focus on “things” more interesting.

The easiest way to use the Find() method with a Predicate is included in this code:

public class person
{
    public int Anni { get; set; }
    public string Nome { get; set; }
    public person(int anni, string nome)
    {
        this.Anni = anni;
        this.Nome = nome;
    }
}
//I assume I have a non-empty list
List<person> agenda = new List<person>();
/* .. load objects from DataBase .. */

//I create a simple search criteria
string personToBeSearched = "mario";
person mario = agenda.Find(delegate(person p) { return p.Nome == personToBeSearched; });

Using the () instead, introduced in the , the code is reduced even more:

//I assume I have a non-empty list
List<person> agenda = new List<person>();
/* .. load objects from DataBase .. */

//I create a simple search criteria
string personToBeSearched = "mario";
person mario = agenda.Find(p => p.Nome == personToBeSearched;);

You can also write an explicit predicate, if you do not like seeing too terse code:

private static bool findTeen(person p)
{
    if (p.Anni < 18)
        return true;
    return false;
}

List<person> BlockBuster_GameOnly = agenda.findAll(findTeen);

We can refine the code even more to take advantage of this methodology not only for the Find() method, but also to other cases of use. Indeed, we can expand our class that represents the data by overriding the Equals() method, as in that other C# example:

public class person
{
    public int Anni { get; set; }
    public string Nome { get; set; }
    public person(int anni, string nome)
    {
        Anni = anni;
        Nome = nome;
    }
    public override bool Equals(object obj)
    {
        if (obj == null) return false;

        person p2 = obj as person;
        if ((object)p2 == null) return false;

        return (this.Anni == p2.Anni) && (this.Nome == p2.Nome);
        //return (this.Anni.Equal(p2.Anni)) && this.Nome.Equal(p2.Nome));
    }
    public override bool Equals(person p2)
    {
        if ((object)p2 == null) return false;

        return (this.Anni == p2.Anni) && (this.Nome == p2.Nome);
        //return (this.Anni.Equal(p2.Anni)) && this.Nome.Equal(p2.Nome));

    }
    public override int GetHashCode()
    {
        return this.Anni ^ this.Nome.Length;
    }
}

In this way, we cannot just do a search based on a single property, but also look for “entities” within a specific list:

person Glauco = new person(36, "Glauco");
if (agenda.Find(p => p.Equals(Glauco)) == null)
    agenda.Add(Glauco);

As you can see from the code, it can be very intuitive and easy to write lambda expressions in simple cases like these, but what happens if we have lists that contain very complex objects? For example, an object that identifies a testCrash of a passenger car, or an object that represents a measurement of a numerical control system for an assembly line, rather than for the detection data of a station’s gas plant. These objects may be very complex and the code becomes almost unreadable. Better to opt for the explicit predicates version. But even in this case, we write a predicate for each different search criteria or for any sort order that we may serve.

We solve by creating a “class predicate” that allows parameters and displays the search method. In this way, we can drastically reduce the predicates that we have to write (although it will be virtually impossible to reduce us to one). We also see a simple example for this case (not to complicate this article) always written in C#:

private class EnvironmentMonitoringResult
{
    //...
    //...
    //...
}

private enum CostructormanagerType
{
    gasMetano = 0,
    gasButano,
    //...
    //...
}

private class myPredicate
{
    private CostructormanagerType impianto;
    private bool dummy;
    private string Parametro1;
    //...
    //...
    //...

    public myPredicate(CostructormanagerType type)
    {
        this.impianto = type;
    }
    public myPredicate(CostructormanagerType type, bool isDummy)
    {
        this.impianto = type;
        this.dummy = isDummy;
    }
    public bool findTipo1(EnvironmentMonitoringResult risultatoMisurazione)
    {
        bool findOK = true;
        switch (this.impianto)
        {
            case CostructormanagerType.gasMetano:
                findOK &= risultatoMisurazione.isNotturno = this.dummy;
                findOK &= risultatoMisurazione.Parametro1 = this.Parametro1;
                //...
                //altri controlli
                break;
            case CostructormanagerType.gasButano:
                break;
            default:
                break;
        }
        //...
        //altri controlli
        return findOK;
    }
    public bool findTipo2(EnvironmentMonitoringResult risultatoMisurazione)
    { ... ... }
}

List<EnvironmentMonitoringResult> misurazioniMensili = new List<EnvironmentMonitoringResult>();

myPredicate ricercaCaso1 = new myPredicate(CostructormanagerType.gasButano, false);

//ricercaCaso1.ParametroX = qualcheCosa
EnvironmentMonitoringResult controlloAllarmeNotturno = misurazioniMensili.Find(ricercaCaso1.findTipo1);

//ricercaCaso1.ParametroY = qualcheCosaAltro
//ricercaCaso1.ParametroZ = stoInventando
EnvironmentMonitoringResult controlloCrashZonaAlfaX = misurazioniMensili.Find(ricercaCaso1.findTipo2);

You can see that even complex searches can be enclosed in a single class and maybe implemented in a separate layer (e.g., EnvironmentService), separate from any interface or BusinessLogic.

Points of Interest

Just as we used anonymous delegates for the Find() method and FindAll() method, we can expand our class by implementing the interface and use the predicates (or Lambda expressions) for the Sort() method too.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here