Click here to Skip to main content
5,787,682 members and growing! (20,455 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » LINQ » General     Intermediate License: The Code Project Open License (CPOL)

A journey into Expressions

By Sacha Barber

A journey into Expressions
C# 3.0, C#.NET, .NET 3.5, LINQ, Architect, DBA, Dev

Posted: 1 Nov 2008
Updated: 1 Nov 2008
Views: 12,067
Bookmarked: 57 times
Note: This is an unedited reader contribution
Announcements
Loading...



Search    
Advanced Search
Sitemap
39 votes for this Article.
Popularity: 7.39 Rating: 4.65 out of 5
0 votes, 0.0%
1
0 votes, 0.0%
2
5 votes, 12.8%
3
3 votes, 7.7%
4
31 votes, 79.5%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Introduction

This article is a short article on the Expressions namespace and how to create Expression Trees manually.

What I'm going to attempt to cover in this article will be:

I think that's quite enough for one article.

A Little History

.NET has evolved over the years, but one of the constants has been the use of delegates. For those that don't know what delegates are they are simply method pointers. Now although not directly related to this articles content, I think it is a good idea to show you a bit about the evolution of delegates leading to lambdas in order for you to understand the rest of the article.

Now it used to be that you used to have to manually create delegates such as this:

    // Declare a delegate type for processing a book:
    public delegate void ProcessBookDelegate(Book book);

    // Maintains a book database.
    public class BookDB
    {

        // Call a passed-in delegate on each paperback book to process it: 
        public void ProcessPaperbackBooks(ProcessBookDelegate processBook)
        {
            foreach (Book b in list)
            {
                if (b.Paperback)
                    // Calling the delegate:
                    processBook(b);
            }
        }
    }

    // Class to test the book database:
    class TestBookDB
    {
        // Print the title of the book.
        static void PrintTitle(Book b)
        {
            System.Console.WriteLine("   {0}", b.Title);
        }

        // Execution starts here.
        static void Main()
        {

            // Create a new delegate object associated with the static 
            // method Test.PrintTitle:
            bookDB.ProcessPaperbackBooks(PrintTitle);

        }
    }	

Blatantly stolen from MSDN http://msdn.microsoft.com/en-us/library/ms173176(VS.80).aspx.

Luckily over the years Microsoft has given us anonymous delegates which allow us to do things like this.

this.Loaded += delegate
{
	MessageBox.Show("in the delegate");
};

Where the signature of this delegate would be something like the following if we had to actually declare it in a non anonymous manner:

internal delegate void MessagDelegate();

Which is all well and good, but sometime you want the ability to create an anonymous delegate that takes a parameter, or maybe even returns a value. Luckily we can still do this using an anonymous delegate, but we must make sure that the delegate type is known at runtime, so we have to provide a a non anonymous delegate signature to use within any method that accepts a anonymous delegate. This allows us to get the correct return type/value.

Here is an example:

internal delegate String UpperCaseAStringDelegate(String s);
....
....
this.Loaded += delegate
{
    ShowIt(delegate(string s)
    {
        MessageBox.Show(s);
        return s.ToUpper();
    });
};
....
....
private void ShowIt(UpperCaseAStringDelegate del)
{
    MessageBox.Show(del("hello"));
}

Now a little bit of time goes by and Microsoft introduced the lambda syntax. There are many great articles on lambdas, I will just show 1 small example comparing them to anonymous delegates, but you will find more on the internet, have a look.

Using the last example we could simply replace the delegate(string s) {...} with a lambda, which would be (s) => {...} here is a reworked example using the lambda syntax:

internal delegate String UpperCaseAStringDelegate(String s);
....
....
this.Loaded += delegate
{
    ShowIt((s) =>
    {
        MessageBox.Show(s);
        return s.ToUpper();
    });
};
....
....
private void ShowIt(UpperCaseAStringDelegate del)
{
    MessageBox.Show(del("hello"));
}

But we can actually go one step further and remove the reliance on the UpperCaseAStringDelegate altogether. We can simple replace it with one of the generic Func<T,TResult> delegates. Where we would then up with the following code:

internal delegate String UpperCaseAStringDelegate(String s);
....
....
this.Loaded += delegate
{
    ShowItLambda((s) =>
    {
        MessageBox.Show(s);
        return s.ToUpper();
    });
};
....
....
private void ShowItLambda(Func<String,String> lambda)
{
    MessageBox.Show(lambda("hello"));
}

Isn't that nicer. That's all I wanted to say in this section, I just wanted you to understand what the Func<T,TResult> delegates and lambdas are actually doing before we move on to some of the more finer details of the Creating Expressions and the Expression namespace.

Creating Expressions

Now that we know about lambdas and some of the Func<T,TResult> delegates, lets proceed to look at Expressions. Expressions came with lambdas. Microsoft have this to say about Expression Trees "Expression trees represent language-level code in the form of data. The data is stored in a tree-shaped structure. Each node in the expression tree represents an expression, for example a method call or a binary operation such as x < y."

So what does that mean to us. Well lets consider the following diagram, where we have one of the generic Func<T,T,TResult> delegates, which means we have a lambda that takes 2 parameters and returns a value. The following illustration shows an example of an expression and its representation in the form of an expression tree.

So you can see from this that we have things like BinaryExpression/ParameterExpression/MemberExpression. Ok, fine. But what would a concrete example look like.

I think the best way to do this is for me to show you some examples. I will show you 2 examples, all based on the following test data

String[] bindings = new String[2] {"NetTcpBinding", "HttpBinding"};
List<Order> orders = new List<Order>{
    new Order {OrderId=1},
    new Order {OrderId=2}
};

Example 1

Let's consider the following:

foreach (String bindingString in
    bindings.Where((x) => x.StartsWith("Net")))
{
    Console.WriteLine("Yields {0}".F(bindingString));
}

This simply uses a lambda within a Where extension method. But could we do this differently, well yeah we could also do the following, where we actually have an Expression<Func<String, Boolean>> variable, which we MUST compile when it is used in the where extension method. Do you see where all this is going?

Expression<Func<String, Boolean>> 
    staticDeclaredExpression = (x) => x.StartsWith("Net");


foreach (String bindingString in
    bindings.Where(staticDeclaredExpression.Compile()))
{
    Console.WriteLine("Yields {0}".F(bindingString));
}

Ok now that you understand the basic idea behind Expressions, maybe its time to see some harder examples.

Example 2

In this example we will be manually creating a lambda that will do the following (o) => o.OrderID==2 to use within a where extension method. Here is the code:

ConstantExpression constOrderId = Expression.Constant(2);

ParameterExpression paramOrder = 
    Expression.Parameter(typeof(Order), "o");

MemberExpression mex = 
    LambdaExpression.PropertyOrField(paramOrder, "OrderId");

BinaryExpression filter = Expression.Equal(mex, constOrderId);
Expression<Func<Order, bool>> exprLambda =
    Expression.Lambda<Func<Order, bool>>(filter, 
        new ParameterExpression[] { paramOrder });


foreach (Order o in orders.Where(exprLambda.Compile()))
{
    ......
}

So a little explanation here, as we are using a object and want to use one of its methods, we need to use a MemberExpression, and as we need to test this against a constant we need to use a ConstantExpression. We also need to test for equality, so we need to use a BinaryExpression. Finally we need to create an overall Expression Tree, which we can do using the Expression.Lambda<Func<T,TResult>>. If you look at the Expression.Lambda method it may begin to make a bit more sense:

Example 3

The last example will be trying to do the following (x) => x.Length > 1 where x is a String:

ConstantExpression constLength = Expression.Constant(1);

ParameterExpression stringParameter = 
    Expression.Parameter(typeof(String), "s");

MemberExpression stringMember = 
    LambdaExpression.PropertyOrField(stringParameter, "Length");


Expression<Func<String, Boolean>> bindLambda =
    Expression.Lambda<Func<String, Boolean>>
    (
        Expression.GreaterThan(
        stringMember,
        constLength),
        stringParameter
    );


foreach (String bindingString in 
    bindings.Where(bindLambda.Compile()))
{
    ....
}

This is much the same as the last example, with the exception that I am building the entire tree using the following Expression.Lambda() method, where I am effectively building the entire Expression Tree in 1 hit.

public static Expression<TDelegate> Lambda<TDelegate>(
    Expression body,
    IEnumerable<ParameterExpression> parameters
)

Expression Namespace

If we have a look at some of the classes available within the System.Linq.Expressions namespace, it gives us a good idea of what could be achieved programmatically.

Covering all these classes is outside the scope of what I wanted to cover in this article. If you want to do more, go for it. Have fun.

We're Done

If you liked the article please vote for it. Thanks.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sacha Barber


Mvp
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

Occupation: Software Developer (Senior)
Location: United Kingdom United Kingdom

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 36 (Total in Forum: 36) (Refresh)FirstPrevNext
GeneralGlad to see this articlememberarhoads764:39 10 Nov '08  
GeneralRe: Glad to see this articlemvpSacha Barber10:40 10 Nov '08  
GeneralOne use of lambda expression generationmemberjpbochi6:47 4 Nov '08  
GeneralRe: One use of lambda expression generationmemberjpbochi6:51 4 Nov '08  
GeneralRe: One use of lambda expression generationmvpSacha Barber7:18 4 Nov '08  
GeneralRe: One use of lambda expression generationmvpSacha Barber7:26 4 Nov '08  
GeneralCall me stupid..memberezazazel10:47 3 Nov '08  
GeneralRe: Call me stupid..mvpSacha Barber11:29 3 Nov '08  
Generallamda => lambdamembertekener23:18 2 Nov '08  
GeneralRe: lamda => lambdamvpSacha Barber1:29 3 Nov '08  
GeneralRe: lamda => lambdamemberdinotsocrates3:56 5 Nov '08  
GeneralRe: lamda => lambdamvpSacha Barber5:20 5 Nov '08  
GeneralRe: lamda => lambdamemberdinotsocrates5:25 5 Nov '08  
GeneralRe: lamda => lambdamvpSacha Barber6:27 5 Nov '08  
GeneralNice onemvpJosh Smith17:27 2 Nov '08  
GeneralRe: Nice onemvpSacha Barber23:00 2 Nov '08  
Generalvery easy to read, great stuffmembermarlongrech10:46 2 Nov '08  
GeneralRe: very easy to read, great stuffmvpSacha Barber23:01 2 Nov '08  
GeneralNice article!memberDmitri Nesteruk23:58 1 Nov '08  
GeneralRe: Nice article!mvpSacha Barber1:53 2 Nov '08  
GeneralRe: Nice article!memberDmitri Nesteruk2:50 3 Nov '08  
GeneralRe: Nice article!mvpSacha Barber3:04 3 Nov '08  
Generalwhy do I always feel so stupid when I read your articles?memberAbu Mami21:12 1 Nov '08  
GeneralRe: why do I always feel so stupid when I read your articles?mvpSacha Barber1:53 2 Nov '08  
GeneralImages..memberTodd Smith18:04 1 Nov '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 1 Nov 2008
Editor: Deeksha Shenoy
Copyright 2008 by Sacha Barber
Everything else Copyright © CodeProject, 1999-2009
Web12 | Advertise on the Code Project