C# Dynamic Function Factory

Building functions instead of expression trees.

The functional programming features of the latest versions of C# allow developers to harness a very expressive programming paradigm to solve challenges in new, elegant ways. Two of the very interesting new features are the “Func<>” delegate and the Lamda expression.

A Lamda expression is a simple expression that is interpreted by the compiler as either a delegate or an expression tree, depending on the Type called for in the given context. You see them used often in LINQ. For example:

   1:  var bostonPeople = people.Where( p => p.City == "Boston" );

Some time has been devoted in explaining how a LINQ query like the above can be created dynamically by building expression trees (see the excellent article: Creating Dynamic Queries in LINQ by Bill Wagner). While this approach to creating a Lambda expression dynamically is very powerful, some may find that it is far more than they need and instead could get by with a simpler implementation. Others may find it difficult to read or understand and therefore provides a challenge in maintenance.

One possible solution is to use the powerful new Func<> and a lambda expression to easily create a function on the fly. This solution is not quite as powerful as building an expression tree but in situations where it’s possible it will save quite a bit of code.

To demonstrate, how about a completely contrived example. Let’s say you have this object in your domain:

   1:  class Person
   2:  {
   3:      public string Name { get; set; }
   4:      public string City { get; set; }
   5:      public string State { get; set; }
   6:  }

and then let’s assume you need to have a way to return back a subset of a collection of “people” based on some criteria that won’t be known until runtime. We can create a factory that builds a function on the fly that we can pass into a LINQ method. Essentially what the “BuildEqFuncFor<T>” method does is build a Func<T, bool> that compares a given value against a named property of T. The signature of the built function is compatible with most LINQ query parameter expectations. (Please excuse the code formatting and naming conventions – I’m trying to fit it into this post.)

   1:  class FunctionFactory
   2:  {
   3:      public static Func<T, bool> BuildEqFuncFor<T>
   4:          (string prop, object val)
   5:      {
   6:          return t => t.GetType()
   7:              .InvokeMember(prop, 
   8:                  BindingFlags.GetProperty, 
   9:                  null, 
  10:                  t, 
  11:                  null) == val;
  12:      }
  13:  }

Now this factory only supports building functions that test for equivalency between some property of some object and a value, however more advanced functions could be constructed using the same concept.

We can now use this FunctionFactory to create a function on the fly and use it in a LINQ method to query our people collection. Let’s see what that looks like:

   1:  var personIsFromBoston = 
   2:      FunctionFactory.BuildEqFuncFor<Person>("City", "Boston");
   3:   
   4:  var bostonPeople = people.Where( personIsFromBoston );
   5:   
   6:  if (bostonPeople.Any())
   7:      bostonPeople.ToList().ForEach(p => Console.WriteLine(p.Name));

Obviously this is a simple example but it could easily be expanded upon (and optimized) to create a more advanced function factory that could generate functions to solve problems beyond just creating dynamic LINQ queries. An issue you should take into account, is there is no compile time type checking so you should take care to handle cases where the type of the property doesn’t match the type of the value, or that the property even exists on the type provided at all.

As an interesting aside… this could be made even a bit more flexible by adding another function layer:

   1:  Func<string, Func<Person, bool>> personIsFrom =
   2:      s => FunctionFactory.BuildEqFuncFor<Person>("City", s);
   3:   
   4:  var bostonPeople = people.Where( personIsFrom("Boston") );

I hope you found this interesting, I look forward to your comments.

7 Comments

  • Here's a more efficient way to do that using LINQ Expressions (System.Linq.Expression):

    public static Func BuildEqFuncFor2(string prop, object val)
    {
    var o = Expression.Parameter(typeof(T), "t");
    Expression<Func> expression = Expression.Lambda<Func>(Expression.Equal(Expression.PropertyOrField(o, prop), Expression.Constant(val)), o);
    return expression.Compile();
    }

  • @Joe Chung

    I linked to an article that demonstrates how to use System.Linq.Expressions - which has been the way we have been doing this for a while.

    The point of my post was to provide an alternative: Building functions INSTEAD of building expression trees. By doing this you get a much more succinct syntax that more clearly expresses what you want to do, instead of how you want it to be done.

    Also, I am not certain that building an expression tree can be considered more efficient. I think it would be an interesting thing to benchmark.

  • I benchmarked this code and found it faster (up to two times faster). I wouldn't have said that it's more efficient otherwise.

    I disagree that your implementation more clearly expresses what you want to do. It may be more succinct in the way that magic constants but only because the LINQ expression API is unnecessarily verbose.

    Anyways, when the CLR gets true metaprogramming support [Anders Hejlsberg, Future of C#, PDC 2008], both our approaches will be obsolete.

  • @Joe Chung

    I'm not sure what benchmarks you were using - but in my experience compiling expressions on the fly has not been "efficient". After reading your comment that it was "twice" as efficient I felt compelled to do my own benchmarks. As it turns out building expressions is much much slower than building functions. See:

    http://weblogs.asp.net/freedomdumlao/archive/2009/02/23/building-functions-vs-building-expressions-performance-comparison.aspx

  • Oh Snap, Joe! You just got C#-served! I'd sure love to see the EXPRESSION on your face now!!

  • Nice comparing, I dig it further in more general way:

  • Simply speaking, if you change the type of property of Person, can building function factory stil work without any improvement?
    Happy coding.
    Wyatt

Comments have been disabled for this content.