Blog Home  Home Feed your aggregator (RSS 2.0)  
Code to Live, Live to Code - The Power of the Predicate<T>
Randy Patterson's BLog
 
 Tuesday, September 18, 2007

The very flexible generic collection List<T> contains several methods that take a predicate as it's parameter.  Coupled with Anonymous Methods this provides powerfully concise code for filtering, searching and sorting your collections.

 

List<Person> People = new List<Person>();
 
People.Add(new Person("Randy", "Patterson", 40));
People.Add(new Person("John", "Smith", 15));
People.Add(new Person("Caity", "Johnson", 13));
People.Add(new Person("Jody", "Patterson", 39));
People.Add(new Person("Chloe", "Dog", 30));
People.Add(new Person("Corey", "Patterson", 18));

 

For Example,  to filter the collection and display only my family members requires a single line of code

IList<Person> family = People.FindAll(delegate(Person person) { return person.LastName == "Patterson"; });
 

And produces the following output

image

To remove the teenagers (not a bad proposition) also requires a single line

People.RemoveAll(delegate(Person person) { return person.Age > 12 && person.Age < 20; });

Sorting

Sorting requires a Comparison<T> delegate instead of Predicate<T> but operates in much the same fashion.

For example, sorting by last name requires this single line of code:

People.Sort(delegate(Person x, Person y) {return x.LastName.CompareTo(y.LastName) ;});

a slight modification will sort the list in descending order:

People.Sort(delegate(Person x, Person y) { return y.LastName.CompareTo(x.LastName); });

To sort by Last Name then First Name would look something like this:

People.Sort(delegate(Person x, Person y)
    {
        if (x.LastName == y.LastName)
            return x.FirstName.CompareTo(y.FirstName);
        else
            return x.LastName.CompareTo(y.LastName);
    });

 

Conclusion

I've just scratched the surface on what the generic List collection is capable of providing. There are several other generic methods that take delegates as parameters, such as ForEach and ConvertAll, that open up interesting possibilities in your code.   Overall I find the Anonymous Method syntax a bit kludgy but C# 3.0 promises to reduce the syntactical noise and give us true (almost) Lambda Expressions

kick it on DotNetKicks.com

Tuesday, September 18, 2007 8:40:57 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [8]   C#  |  Trackback
Thursday, September 20, 2007 12:05:51 PM (Eastern Daylight Time, UTC-04:00)
that's brillant
anonymous
Thursday, September 20, 2007 12:44:26 PM (Eastern Daylight Time, UTC-04:00)
This is all wrong man.
Scott
Thursday, September 20, 2007 12:46:07 PM (Eastern Daylight Time, UTC-04:00)
This is all wrong man. Unreal dude.
Scott
Thursday, September 20, 2007 12:47:36 PM (Eastern Daylight Time, UTC-04:00)
Can you show me how to do it in Visual Basic?
Scott
Thursday, September 20, 2007 1:44:29 PM (Eastern Daylight Time, UTC-04:00)
How would you go about unit testing delegate methods?


"People.RemoveAll(delegate(Person person) { return person.Age > 12 && person.Age < 20; });"

Using your example, what we have is a simple way to prevent creating a new method (ie the IsTeen(person) method). But, as the delegate methods get complex it becomes difficult to read, debug, or test. At what point does it become too complex to use this approach? Is there a rule of thumb?
Thursday, September 20, 2007 3:24:36 PM (Eastern Daylight Time, UTC-04:00)
Another thing to remember when using anonymous methods, is that Debug-Continue will not work in Visual Studio. Just something to keep in mind
David
Friday, September 21, 2007 5:08:35 AM (Eastern Daylight Time, UTC-04:00)
I agree that this is a most compelling feature and will reduce code amount and complexity. However I wonder whether the code becomes too simple. E.g. what about null checks (will NullReferenceException replace ArgumentNullException?). What about consistency (e.g. in one place using case sensitive comparison, case insensitive in the other. Identifying a person by name in onle place. Also checking the birth date in the other.)

Due to lambdas we _will_ see this code more often. To the good or the bad? I don't know.
Friday, September 21, 2007 7:28:28 AM (Eastern Daylight Time, UTC-04:00)
It is not a requirement to use anonymous methods for Predicate<T> or Comparison<T> parameters but, when it makes sense, it produces concise and easily readable code. However, when anonymous methods are misused it can produce code that is difficult to maintain. Like most features, the “trick” is determining when it becomes a benefit and when it becomes the bane of your existence.

When to use Anonymous methods:

1. Single use code snippet
2. Logic is less than 5 lines of code.
3. The intent can clearly be seen in the code, otherwise a method name would better express intent (i.e method name of SortByLastNameThenFirstName)

When <B>not</B> to use Anonymous methods:

1. Code is used multiple times.
2. Requires a Unit Test
3. Code is complex enough to obfuscate intent with a quick review.

These are just guidelines and you will, no doubt, amend them as you become more comfortable using anonymous methods
Randy Patterson
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, sup, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview
Copyright © 2008 Randy Patterson. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.