Explaining advanced features of C# 3.0

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 methods

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<TResult>

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.0

Expression<TDelegate>

Of particular note is the difference between Func<TResult> and Expression<TDelegate>. A Func<TResult> is code (a delegate) that is compiled at runtime, while an Expression<TDelegate> is a data representation (as an Expression Tree) of that delegate. This means you can act upon any part of an Expression<TDelegate> as if it were a data structure (similar to getting a count of objects in a list or accessing a dictionary value via dictionary key).

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:

    Expression
  • Parameter
  • Body
    • –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.lostechies.com/blogs/gabrielschenker/archive/2009/02/03/dynamic-reflection-versus-static-reflection.aspx
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);
        }
    }

Flattr this!

2 thoughts on “Explaining advanced features of C# 3.0”

Comments are closed.