C# 3.0 Func delegates and Expressions
In this post, I’ll attempt to clarify the meaning of Func delegates and Expressions.
These are very useful additions to C# 3.0, but it seems to be rarely blogged about.
// Note: I assume you have a general understanding of delegates and anonymous method
Microsoft’s definitions:
Func
// Encapsulates a method that has no parameters and returns
// a value of the type specified by the TResult parameter.
public delegate TResult Func<TResult>()
public delegate TResult Func<TParam0, TResult>(TParam0 arg0)
public delegate TResult Func<TParam0, TParam1, TResult>(TParam0 arg0, TParam1 arg1)
// etc. up to 3 Generic Input parameters and a Generic Result parameter
Expression
// Represents a strongly typed lambda expression as a data structure
// in the form of an expression tree. This class cannot be inherited.
public sealed class Expression<TDelegate> : LambdaExpression
// Describes a lambda expression.
public class LambdaExpression : Expression
// Provides the base class from which the classes that represent expression
// tree nodes are derived. It also contains static (Shared in Visual Basic)
// factory methods to create the various node types. This is an abstract class.
public abstract class Expression
// NOTE : Expression<TDelegate> is not an override of Expression, they are completely independent classes
Quick Rundown
Func
The Func delegates are simply Generic delegates introduced to make our lives easier. You specify your return type, or the types of your input parameters and your return type.
For instance, assume you have an object called Product, with a method whose signature is:
public bool AddComponent(Component c) { /* logic */
You could use the Func delegate in a number of ways on the product object:
// our objects
Product product = new Product();
// Examples
Func<bool> addComponent1 = product.AddComponent( new Component() );
Func<bool> addComponent2 = delegate() { return product.AddComponent( new Component() ); };
Func<bool> addComponent3 = () => product.AddComponent( new Component() );
if(addComponent1()) { /* Do stuff */ }
if(addComponent2()) { /* Do stuff */ }
if(addComponent3()) { /* Do stuff */ }
The above example is the common explanation of Func delegates. However, to a beginner, this may seem like a ridiculous way to rename a method. The point being, it can be difficult to understand why you’d generalize
product.AddComponent( new Component() )
as ‘addComponent1’ when you could just as easily write out
if(product.AddComponent( new Component() ) ) { /* Do stuff */ }
Another, more useful example of a real-world application:
Product product = new Product();
Func<bool> addAllProducts = () =>
{
if (product.AddComponent(new Component { Name = "Component1" })
&& product.AddComponent(new Component { Name = "Component2" })
&& product.AddComponent(new Component { Name = "Component3" }))
{ return true; }
else { return false; }
};
bool wasSuccessful = addAllProducts(); // wasSuccessful is true if AddComponent succeeds every time.
// NOTE: Here, I've used object instantiation for the Component object, this is another feature of C# 3.
Expression
Of particular note is the difference between Func
You’ve probably read that paragraph and said “…what?” If so, I don’t blame you.
Take, for instance, the example given at MSDN:
System.Linq.Expressions.Expression<Func<int, bool>> expr = (i) => i < 5
This doesn’t give us much to go by. However, when you think about expr as a data structure, you’re basically instantiating this data structure with ‘i => i < 5;’. Now, you can pass this expression tree around your application and you’re free to access any part of the expression tree as if it is its own separate entity; you can’t do this with a delegate alone. A fairly good example is available at MSDN.
To better clarify, let’s look at the parts of this expression tree:<ul style="padding:0;margin:0;>
- –Operation
- –Constant
/* Expression */ (i) => i < 5;
/* Parameter */ (i)
/* Body */ i < 5;
/* Operation NodeType */ <
/* Constant */ 5
I know breaking it down into these parts seems very simplistic, but the point is that you can’t do this with a delegate. If you passed a delegate to a method, that’s it. You can’t figure out what the first parameter was declared as, or the operation being performed (less than, greater than, etc). You’d have no way of finding what constant was supplied.
To compile the above Expression tree, you could do the following:
bool oneIsLess = expr.Compile()(1); /* result: true *
Why is this important? You can easily access the parts of the expression as described by the MSDN article:
Expression<Func<int, bool>> exprTree = num => num < 5;
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
// This code produces the following output:
// Decomposed expression: num => num LessThan 5
Using the Expression Tree Visitor from MSDN, you can access the parts of a number of Expression Trees.
Practical Applications
Because this post is already very long, instead of going in-depth into practical applications now, I’ll save that for a future post.
Instead, I’d like to direct you to the project and usage of Expression trees that made me delve further into the topic: Fluent NHibernate. I had previously thought that Expression Trees and Lamda Expressions were geared more toward LINQ providers and less important for daily development. However, if you were to download the source for Fluent NHibernate, you’d see another cool usage of Expression Trees: static reflection.
James Gregory, the principal developer of Fluent NHibernate wrote a nice introduction to static reflection, in which he illustrates the following usage:
/* Copyright James Gregory, Creative Commons:Attribution-Non-Commercial-Share Alike 2.0 UK: England & Wales */
public PropertyInfo GetProperty<TEntity>(Expression<Func<TEntity, object>> expression) { /* Do stuff */ }
GetProperty<Customer>(customer => customer.Name); // usage
As you can see, instead of retrieving the PropertyInfo of the Customer object’s Name property by hard-coding a “Name” string, you’re now free to refactor your code properly. In which case, if you were to change your ‘Name’ property, your tests or build process would fail, whereas the hard-coded string “Name” would be overlooked.
I encourage you to download the source code for Fluent NHibernate and take a look at how static reflection is being used.
Further Reading
http://www.codeproject.com/Articles/36262/Getting-Fun-with-Net-Static-Reflection.aspx
http://ayende.com/Blog/archive/2005/10/29/StaticReflection.aspx
http://apobekiaris.blogspot.com/2009/06/more-static-reflection.html
Example Console Application
static void Main(string[] args)
{
List<int> numbers = new List<int>();
Random r = new Random();
for (int i = 0; i < 15; i++)
{
numbers.Add(r.Next(0,50));
}
// Expression trees can be used to perform an action on objects
Expression<Func<List<int>,int, bool>> isAvailable = (x,num) => x.Contains(num);
for (int i = 0; i < 50; i++)
{
Console.WriteLine("Is {0} available? {1}", i, isAvailable.Compile()(numbers, i));
}
Product product = new Product();
Func<bool> addAllProducts = () =>
{
if (product.AddComponent(new Component { Name = "Component1" })
&& product.AddComponent(new Component { Name = "Component2" })
// && product.AddComponent(new Component { Name = "Component2" }) /* fails */
&& product.AddComponent(new Component { Name = "Component3" }))
{ return true; }
else { return false; }
};
bool wasSuccessful = addAllProducts();
System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;
ParameterExpression param = (ParameterExpression)expr.Parameters[0];
BinaryExpression operation = (BinaryExpression)expr.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
}
}
public class Product
{
public IList<Component> Components { get; private set; }
public bool AddComponent(Component c)
{
if (Components.Contains(c))
return false;
else
{
Components.Add(c);
return true;
}
}
public Product()
{
Components = new List<Component>();
}
}
public class Component
{
public string Name { get; set; }
public override bool Equals(object obj)
{
if(!(obj is Component)) { return false; }
return this.Name.Equals(((Component)obj).Name);
}
}