Predicates, Actions, and Comparison's oh my...

Tonight I was playing with some code trying to wrap my head around the usefulness of anonymous methods.  I started looking at some sample code in various places that all failed to “click”.  I eventually stumbled upon a couple posts by Mitch Danny's blog that helped me see the light.  The generic collection classes have a number of different methods for working with items within the collection such as Find, FindAll, and ForEach. 

The Find, and FindAll methods have a single Predicate<T> parameter.  Using FindAll along with the generic Predicate<T> delegate can help you to filter a list of objects very easily.  Let’s start with a little boiler plate code.  First I defined a Customer class with a single Age field:

public class Customer {
   public Customer() { }
   public Customer(int age) {
     this.Age = age;
   }
   public int Age = 10;
}

Let’s now assume that we want to get all customers that have an age greater then 20.  We’ll start with a generic list class containing a couple sample customers:

List<Customer> customers = new List<Customer>();
customers.Add(new Customer(19));
customers.Add(new Customer(21));
customers.Add(new Customer(20));
customers.Add(new Customer(40));
Assert.AreEqual(4, customers.Count);

In order to begin filtering our list of customers we can use the FindAll(Predicate<T> method on the generic list class along with an anonymous method (since that’s what we started off trying to learn about).  The logic within the anonymous method will get called for each customer in our list.  If the anonymous method returns true (if the customer’s age is greater then 20) then the customer will get added to the list of customers that will be returned from the FindAll method.

List<Customer> customersOver20 = customers.FindAll(delegate(Customer customer)  {
      return customer.Age > 20;
   }
);
Assert.AreEqual(2, customersOver20.Count);

To make this a little more clear the code can be broken out into this:

Predicate

<Customer> customersOver20Predicate = delegate(Customer customer)  {
   return customer.Age > 20;
};

List<Customer> customersOver20 = customers.FindAll(customersOver20Predicate);
Assert.AreEqual(2, customersOver20.Count);

First we declare our predicate delegate, and then we pass the predicate to the FindAll method on our generic list.  Pretty sweet if you ask me.  I’m only beginning to think about all the different ways this could be used but it seems pretty exciting.

We’re not done yet.  We can also take advantage of the Comparison<T> delegate as well as the Action<T> delegate.  The Comparison<T> delegate allows us to implement sorting within customer collections like so:

customers.Sort(delegate(Customer c1, Customer c2) {
  return c1.Age.CompareTo(c2.Age);
}
);

The Sort method takes a Comparison<T> delegate, which we use to implement sorting by age.  The final thing that we’ll use is the Action<T> delegate to list out the items in our list via the generic lists ForEach method.

customers.ForEach(delegate(Customer c)  {
      Console.WriteLine(c.Age);
   }
);

Although I didn’t really find out that much about anonymous delegates I did discover a whole bunch of cool shit that’s within the generic collection classes (Find, FindAll, etc.) as well as a bunch of interested predefined delegates that work with generic types Predicate<T>, Comparison<T>, and Action<T>.  A big shout out goes to Mitch Denny for his list of articles that introduced me to such a wonderful little nicety within .NET 2.0.

# re: Predicates, Actions, and Comparison's oh my...

Monday, April 25, 2005 9:53 PM by Mitch Denny    
Glad you liked the posts :)

# re: Predicates, Actions, and Comparison's oh my...

Monday, April 25, 2005 9:57 PM by ade    
Take a look at:
<a target="_new" href="http://martinfowler.com/bliki/Closures.html">http://martinfowler.com/bliki/Closures.html</a>
<a target="_new" href="http://ivan.truemesh.com/archives/000392.html">http://ivan.truemesh.com/archives/000392.html</a>
<a target="_new" href="http://ivan.truemesh.com/archives/000411.html">http://ivan.truemesh.com/archives/000411.html</a>
<a target="_new" href="http://ivan.truemesh.com/archives/000425.html">http://ivan.truemesh.com/archives/000425.html</a>

which are articles showing how these techniques work in other languages. Since they also use 30 year old names for these techniques, rather than inventing a new name, you should find it easier to track down the large amount of prior art in this field.

# Re: Predicates, Actions, and Comparison's oh my...

Monday, April 25, 2005 11:16 PM by Yves Reynhout    
<a target="_new" href="http://weblogs.asp.net/yreynhout/archive/2005/04/05/397114.aspx">http://weblogs.asp.net/yreynhout/archive/2005/04/05/397114.aspx</a>

# Closures / Anonymous Delegates as DDD Specifications

Wednesday, April 27, 2005 8:15 AM by Steve Eichert    
Closures / Anonymous Delegates as DDD Specifications

# re: Predicates, Actions, and Comparison's oh my...

Wednesday, November 09, 2005 2:27 PM by Alex    
What would be really cool would if someone figured out how to write a dynamic method that took something like SQL or OPath and converted it to a Predicate under the hood so rather than having to deal with Predicates and Dynamic Delegates which I think is frankly beyond most people, they could do something like this:

Customers.FindAll("WHERE FirstName = 'Fred'");

Now I think that is much more understandable for the average person.

I am looking at doing this in Base4. So that people can essentially treat in Memory Collections just like they treat the database.

i.e. I want to have something that converts a Predicate to an ObjectPath statement (so I can execute a Predicate against the database) and an ObjectPath statement into a Predicate (so I can execute an ObjectPath against an in memory collection).

If you can do this then the API looks a lot more consistent.



# re: Predicates, Actions, and Comparison's oh my...

Thursday, January 10, 2008 9:58 AM by cristina mcdaniel    
not to much info on this

# re: Predicates, Actions, and Comparison's oh my...

Thursday, January 10, 2008 9:58 AM by cristina mcdaniel    
not to much info on this

Post a Comment

 
 
Prove you're not a spammer: 
4 + 4 =