Predicates in Action

Generics offer tremendous flexibility – in more ways than you would ever know. Predicates are a good example for this. .NET 2.0 BCL comes with certain generic delegates – Action<T>, Predicate<T>, and Converter<Tin, Tout> respectively. Their definitions are given below:

public delegate TOutput Converter<TInput, TOutput>(TInput input);

public delegate void Action<T>(T obj);

public delegate bool Predicate<T>(T obj);

If you look at the definitions, you can guess that the instances of these delegates hold references to methods that do type specific operations. For example, the Predicate delegate represents a method which takes an instance as parameter, and determines if the instance meets a particular criteria. Quite obviously, these delegates would be most applicable to generic collections and arrays. The List<T> class for instance, employs them  in Find, FindAll, Exists, FindIndex, FindLastIndex, ForEach methods. You could find similar usages in the Array class.

The real cool thing is using predicates in concert with anonymous methods. At first, it may look convoluted, but actually, that makes coding real easy (and fun). The oversimplified code snippet given below does a couple of things – given a list of accounts, it finds all accounts with a zero balance, and for each of these accounts sends a mail notifying the same. The FindAll method uses a Predicate<T> delegate and the ForEach delegate employs the Action<T> delegate.

List<Account> accounts = GetAllAccounts();
accounts.FindAll(
        
// Uses the Predicate<T> delegate
        
delegate(Account account)
        {
            
return (account.Balance == 0);
        }
    ).ForEach
    (
        
//Uses the Action<T> delegate
        
delegate(Account account)
        {
            SendMail(account, "Be aware, you now have a zero balance");
        }
    );

What you may have noticed is that we have completed avoided nested for/foreach loops here. I have used anonymous methods inline here, but you can easily replace them with delegate instances so as to accommodate different criteria or action items at runtime. In more advanced cases, you could generate predicates at runtime based on user provided business rules or something like that.

Thus is the amount of flexibility could can reap out of generics! I would strongly recommend one to go over this interesting MSDN Magazine article on Predicates by Ken Getz to get a better idea.

6 thoughts on “Predicates in Action”

  1. Hi Manoj,

    Wouldn’t LINQ simplify this even further with lambda expressions? I think the following piece of code does the same

    var accounts = GetAllAccounts();
    var mailList = accounts.Where(a => a==0);
    mailList.ForEach(account => SendMail(account, “Be aware, you now have a zero balance”));

  2. One good thing about using an anonymus method is that it allows you to access locals from the enclosing scope. With a first class delegate you cannot pass in any search parameters to the collection, but with anonymity you can easily use whatever local variables you need from the outer method as your search parameters

  3. FindAll allocate, populate and return a new List, plus the syntax is quite unclear.

    foreach( Account account in GetAllAccounts() ) {
    if( account.Balance == 0 ) {
    SendMail( account, “Be aware, you now have a zero balance” );
    }
    }

    Done.

  4. This could be written in one line as below:

    GetAllAccounts().Where(a => a == 0).ToList().ForEach(account => SendMail(account, “Be aware, you now have a zero balance”));

  5. @Surjit :

    That’s both brief & clear. Brilliant !

    Needed a tine tweak : a.Balance == 0

    GetAllAccounts().Where(a => a.Balance == 0).ToList().ForEach(account => SendMail(account, “Be aware, you now have a zero balance”));

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>