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.