Generic Expression Builder
I blogged about fluent interfaces and expression builders a couple of times before. For this post, I want to share a base class that I’ve been using for taking away some of the burden when creating expression builders for domain classes.
Here’s the expression I’m after:
var document = DocumentBuilder.BuildDocument()
.AuthoredBy("Stephen Hawking")
.Titled("The Universe in a Nutshell")
.TaggedWith(tag => tag.Named("Physics"))
.Build();
This creates an instance of a domain class named Document with the name of the author, its title and with an associated tag. Let me first show the code of the expression builders that make this happen.
public interface IDocumentAuthorBuilder { IDocumentTitleBuilder AuthoredBy(String author); } public interface IDocumentTitleBuilder { IDocumentTagBuilder Titled(String title); } public interface IDocumentTagBuilder : IBuilder<Document> { IDocumentTagBuilder TaggedWith(Action<ITagBuilder> buildUsing); } public class DocumentBuilder : Builder<Document>, IDocumentAuthorBuilder, IDocumentTitleBuilder, IDocumentTagBuilder { private DocumentBuilder() {} public static IDocumentAuthorBuilder BuildDocument() { return new DocumentBuilder(); } IDocumentTitleBuilder AuthoredBy(String author) { ProvideValueFor(document => document.Author, author); return this; } IDocumentTagBuilder Titled(String title) { ProvideValueFor(document => document.Title, title); return this; } public IDocumentTagBuilder TaggedWith(Action<ITagBuilder> buildUsing) { var tagBuilder = new TagBuilder(tag => ProvideValueFor(document => document.Tags, tag)); buildUsing(tagBuilder); return this; } } public interface ITagBuilder { void Named(String name); } public class TagBuilder : ITagBuilder { private readonly Action<Tag> _afterBuildAction; public TagBuilder(Action<Tag> afterBuildAction) { _afterBuildAction = afterBuildAction; } public void Named(String name) { var tag = new Tag(name); _afterBuildAction(tag); } }
The expression builders all provide progressive interfaces. Also notice that the DocumentBuilder derives from a base class named Builder. This class provides a method ProvideValueFor that is used to feed the base class with the name of a property and a corresponding value. Collections are also supported. Here’s the code for the Builder class.
public interface IBuilder<T> { T Build(); } public abstract class Builder<T> : IBuilder<T> { private Dictionary<PropertyInfo, Object> PropertiesAndValues { get; set; } protected Builder() { PropertiesAndValues = new Dictionary<PropertyInfo, Object>(); } public static implicit operator T(Builder<T> builder) { return builder.Build(); } protected void ProvideValueFor(Expression<Func<T, Object>> expression, Object value) { var property = ReflectionHelper.GetProperty(expression); if(false == PropertiesAndValues.ContainsKey(property)) RegisterPropertyAndValue(property, value); else SetPropertyAndValue(property, value); } private void SetPropertyAndValue(PropertyInfo property, Object value) { if(IsCollection(property)) { var values = (List<Object>) PropertiesAndValues[property]; values.Add(value); } else { PropertiesAndValues[property] = value; } } private void RegisterPropertyAndValue(PropertyInfo property, Object value) { if(IsCollection(property)) PropertiesAndValues.Add(property, new List<Object>() { value }); else PropertiesAndValues.Add(property, value); } private static Boolean IsCollection(PropertyInfo property) { if(property.PropertyType == typeof(String)) return false; var collectionType = typeof(IEnumerable<>); return IsCollectionOfType(collectionType, property.PropertyType); } private static Boolean IsCollection(FieldInfo field) { var collectionType = typeof(ICollection<>); return IsCollectionOfType(collectionType, field.FieldType); } private static Boolean IsCollectionOfType(Type collectionType, Type type) { if(collectionType.Name == type.Name) return true; var interfaces = type.GetInterfaces(); return interfaces.Has(@interface => @interface.Name == collectionType.Name); } public T Build() { var typeToBuild = typeof(T); if(false == HasParameterlessConstructor(typeToBuild)) throw new InvalidOperationException( "No parameterless constructor."); var instance = (T)Activator.CreateInstance(typeToBuild, true); foreach(var entry in PropertiesAndValues) { var property = entry.Key; if(IsCollection(property)) SetCollectionValuesFor(property, instance, (List<Object>) entry.Value); else SetValueFor(property, instance, entry.Value); } return instance; } private static Boolean HasParameterlessConstructor(Type type) { const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; var defaultConstructor = type.GetConstructor(bindingFlags, null, new Type[0], null); return null != defaultConstructor; } private static void SetValueFor(PropertyInfo property, T instance, Object value) { property.SetValue(instance, value, null); } private static void SetCollectionValuesFor(PropertyInfo property, T instance, List<Object> values) { var backingField = BackingFieldResolver.GetBackingField(property); if(false == IsCollection(backingField)) { var message = String.Format( ResourceLoader<Builder<T>> .GetString("InvalidCollectionType"), property.Name); throw new InvalidOperationException(message); } var collection = property.GetValue(instance, null); foreach(var value in values) { const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod; backingField.FieldType .InvokeMember("Add", bindingFlags, null, collection, new[] { value }); } } }
Using this approach, its no longer necessary to make any compromise of exposing property setters or a dedicated constructor just for serving the expression builders. The Builder class uses refection to set the value of a property or to fill a collection. The BackingFieldResolver is a class I picked up from this post. Very cool stuff!
I have only used this approach in a couple of side projects, but let me know you think.
Till next time.






I have a (configurable, multi-tenant) navigation system, where I have to set up pages with a bunch of properties and relationships. Without the builder, I have either created (the initial configuration) pages directly from the constructor, or from a factory. Both ways, the code very quickly ends up looking a mess.
Now I have something like this:
var security = NavigationBuilder
.ForApplication(Application.Security)
.ForTenant(Root.Tenant)
.AddPages(
PageBuilder.Named(”main”),
PageBuilder.Named(”home”).AsController(),
PageBuilder.Named(”dashboard”),
PageBuilder.Named(”administration”).ForParent(”main”).AsController()
)
.Build();
The indentation inside AddPages is simply there to make it a bit more readable.
Ah, ok, the indentation has disappeared. But it’s there in spirit.
@Valeriu Caraulean
And I guess that code is a configuration API.
Is there a reflectionhelper class that goes with this?
@Valeriu: Expression builders are especially useful to create and set up an entire aggregate root with all its entities and value objects. No place for behavior. I was just making a point against setters on domain objects.
@Johnny: Agreed on getters. Very hard to do and I’ve learned to live with them. Using static analysis for preventing procedural abuse. The code is part of a small sample app I’ve been working on. Maybe at a given point I’ll put it out there somewhere.
This is the code for the ReflectionHelper class.
http://snipplr.com/view/17521/reflectionhelper/
That’s indeed a cool usage of the backing field resolver. Glad that it is useful to you!