Posts
208
Comments
1144
Trackbacks
51
C# 3.0 Lambda Expressions replacing Anonymous Methods

C# 3.0 Lambda Expressions play an integral part of making the LINQ framework work.  However, even apart from LINQ, they stand alone quite nicely as a great replacement to C# 2.0 anonymous methods in terms of language syntax usability.  For example, consider this simple anonymous method:

personList.RemoveAll(delegate(Person person)
{
    return person.DateOfBirth.Year < 1980;
});

While anonymous methods were a great language addition in C# 2.0, the syntax could be confusing at times in terms of getting the delegate signature correct and the curly braces all lined up in the right place.  In C# 3.0 this exact snippet of code can be re-written with Lambda expressions in a much more readable 1 line of code:

personList.RemoveAll(p => p.DateOfBirth.Year < 1980);

What's even more interesting here is that both snippets generate the EXACT same MSIL:

L_000f: ldsfld class [mscorlib]System.Predicate`1<class ConsoleApplication1.Person> ConsoleApplication1.Program::<>9__CachedAnonymousMethodDelegate2
L_0014: brtrue.s L_0029
L_0016: ldnull
L_0017: ldftn bool ConsoleApplication1.Program::<Main>b__0(class ConsoleApplication1.Person)
L_001d: newobj instance void [mscorlib]System.Predicate`1<class ConsoleApplication1.Person>::.ctor(object, native int)
L_0022: stsfld class [mscorlib]System.Predicate`1<class ConsoleApplication1.Person> ConsoleApplication1.Program::<>9__CachedAnonymousMethodDelegate2
L_0027: br.s L_0029
L_0029: ldsfld class [mscorlib]System.Predicate`1<class ConsoleApplication1.Person> ConsoleApplication1.Program::<>9__CachedAnonymousMethodDelegate2
L_002e: callvirt instance int32 [mscorlib]System.Collections.Generic.List`1<class ConsoleApplication1.Person>::RemoveAll(class [mscorlib]System.Predicate`1<!0>)

Notice the b__0 method - just like normal 2.0 anonymous methods the compiler is generating a hidden method behind the scenes to handle the delegate:

[CompilerGenerated]
private static bool <Main>b__0(Person person)
{
    return (person.DateOfBirth.Year < 0x7bc);
}

so I guess I just like the way the code becomes less verbose and easier to understand at the same time.  As an additional example, think about the ForEach<T>() anonymous method on the List<T> class in 2.0:

personList.ForEach(delegate(Person person)
{
    Console.WriteLine(person.ToString());
});

While nice, I always felt like it would just be a lot easier to write that statement like this:

foreach (Person person in personList)
{
    Console.WriteLine(person.ToString());
}

But now, with Lambda expressions, we finally have syntax that truly is more concise without losing readability:

personList.ForEach(p => Console.WriteLine(p.ToString()));

posted on Wednesday, August 15, 2007 9:21 PM Print
Comments
Gravatar
# re: C# 3.0 Lambda Expressions replacing Anonymous Methods
tobsen
8/19/2007 7:33 AM
Nice article. I hope I will get used to those Lambda expressions. I currently use the foreach loop and have never put that to question. I really have to take a look into the 3.0 Framework I guess...
Gravatar
# re: C# 3.0 Lambda Expressions replacing Anonymous Methods
Alexandre Grenier
11/27/2007 6:42 PM
The best part is that you can apply the same design principle as the List object in your own classes. Very useful for business rules!

Here is an example based on tidbits from my C# 3.0 stocks trading platform.

1. define a generic rule object

public class Rule<T>
{
public Func<T, bool> ApplicabilityRule { get; internal set; }
public Func<T, bool> ConformanceRule { get; internal set; }
}


2. create a list of actual rules

var rules = new List<Rule<OrderRequest>>
{
new Rule<OrderRequest>
{
ApplicabilityRule = o => o.RequestType == RequestType.Place,
ConformanceRule = o => o.Order.Quantity > 0
},

new Rule<OrderRequest>()
{
ApplicabilityRule = o => o.RequestType == RequestType.Place,
ConformanceRule = o => o.Order.Symbol != ""
}
};


3. create an object that should conform to the rules

var orderRequest = new OrderRequest
{
RequestType = RequestType.Place,
Order = new Order { Symbol = "GOOG", Quantity = 100 }
};


4. get a list of applicable rules and test for conformity

var applicableRules = rules.FindAll(r => r.ApplicabilityRule(orderRequest));

var brokenRules = applicableRules.FindAll(r => !r.ConformanceRule(orderRequest));

5. do what you need to do

if (brokenRules.Count == 0) orderRequest.Execute()
else orderRequest.Cancel(brokenRules);


Let your imagination go wild and harness the power of lambda expressions... happy coding!

Alexandre Grenier

Post Comment

Title *
Name *
Email
Comment *  
Verification

View Steve Michelotti's profile on LinkedIn

profile for Steve Michelotti at Stack Overflow, Q&A for professional and enthusiast programmers




Google My Blog

Tag Cloud