|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
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
IntroductionThis 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 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 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 Creating ExpressionsNow that we know about lambdas and some of the So what does that mean to us. Well lets consider the following diagram, where we have one of the generic
So you can see from this that we have things 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 1Let'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 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 2In this example we will be manually creating a lambda that will do the following 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
Example 3The last example will be trying to do the following 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 public static Expression<TDelegate> Lambda<TDelegate>(
Expression body,
IEnumerable<ParameterExpression> parameters
)
Expression NamespaceIf we have a look at some of the classes available within the
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 DoneIf you liked the article please vote for it. Thanks.
|
||||||||||||||||||||||