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.