Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Factory Method Pattern With Expression Trees using C#

0.00/5 (No votes)
31 Dec 1899 1  
Efficient Factory Method Pattern Implementation in C# using Expression Trees

Introduction  

Well, the sole purpose of writing this article is not to tell you what a factory class or factory method pattern is.

I am sure there are better known articles already published in web space.

On the contrary, I am trying to tell you a new efficient way to implement the factory class using Expression trees rather than using Reflection. 

Background          

Try To Read About Factory Method Pattern Implementation using C#.  

Here is an article to help you kick start with:-  

http://www.codeproject.com/Articles/9319/Creating-a-Class-Factory-with-C-and-NET 

Using the code   

OK, so let’s understand how to create an object using Factory method pattern by using Reflection first. 

Here is our sample factory class diagram:- 

Well to make a simple Reflection based Factory Class for creating our shirt type on the basis of type name, here is what is required:-

  1. Create a Dictionary with Shirt Type Name [String] as key and Shirt Type [Type] as value.   

  2. User Activator (System. Activator) to create an instance of Type for the supplied shirt type name. 

Below is the code:- 

public Shirt CreateShirt(string shirtType, Color color, string brand)
{
if (!_types.ContainsKey(shirtType)) 
    return null;

var t = _types[shirtType];
return Activator.CreateInstance(t, color, brand) as Shirt;
}

Problem with System Activator: 

Well you might be wondering what is wrong with the above code, let me tell you how Activator’s CreateInstance works or rather actually creates an instance to understand why it is slow and need to be replaced. 

Here is the definition of CreateInstance Method:- 

public static object CreateInstance(Type type, params object[] args);

The first parameter is the type you want the activator to create an object. Internally, the activator will search this type from its name in metadata.   

Next argument is object array with params keyword, which means you can supply parameters without making an array. 

Internally, activator will try to search for a constructor in the type whose parameters match in number, order, and type with the arguments supplied in the form of object array to CreateInstance method.  

If args array is an empty array or null, the constructor that takes no parameters (the default constructor) is invoked. 

Now because it is searching through the type using Reflection, which internally always searches on strings, it turns out to be slow at run-time. 

For the above shirt factory, it took around 4.74 seconds on my Core 2 Duo, 4GB Ram Machine, when I ran the CreateShirt Method for a million times. 

sysActFactory.CreateShirt("Tee", Color.Blue, "Reebok");

Now Let’s see what is the fix

Expression Trees Come To Rescue  

OK, so how does Expression Trees help in this scenario?  

If you try to dissect activator’s CreateInstance method, you will notice that it’s the metadata search that it has to do every time before invoking the object, that makes it slow. 

So I decided, that if somehow I can replace this search through metadata my making expressions at compile time, I will be left with only invoking the expression at runtime. 

Well, it was easy, why not supply the right constructor at compile time and then make an Expression out of it. We can then call this expression at runtime, which will be much like invoking the constructor directly. 

Make sense? Let’s see… 

Let’s start by having our custom Activator delegate with the same signature as CreateInstance.

public delegate object Activator(params object[] args);

We will use this delegate to convert our expression to and return from our Activator Creation Method.

Here is how the method looks like:-

       
        private static TDelegate DoGetActivator<TDelegate>(ConstructorInfo ctor)  
        where TDelegate : class
        {
            var ctorParams = ctor.GetParameters();
            var paramExp = Expression.Parameter(typeof (object[]), "args");

            var expArr = new Expression[ctorParams.Length];

            for (var i = 0; i < ctorParams.Length; i++)
            {
                var ctorType = ctorParams[i].ParameterType;
                var argExp = Expression.ArrayIndex(paramExp, Expression.Constant(i));
                var argExpConverted = Expression.Convert(argExp, ctorType);
                expArr[i] = argExpConverted;
            }

            var newExp = Expression.New(ctor, expArr);
            var lambda = Expression.Lambda<TDelegate>(newExp, paramExp);            
            return lambda.Compile();
        }

Next you can simple wrap it up in an extension method and replace the TDelegate Type With Activator Type.  

Here is how it looks like:- 

public static Activator GetActivator(this ConstructorInfo ctor)
{
   return DoGetActivator<Activator>(ctor);
}

You can have another extension of Type that looks like this:-

public static Activator GetActivator(this Type type)
        {
            var ci = type.GetConstructors(BindingFlags.Instance |BindingFlags.Public).FirstOrDefault();

            return ci.GetActivator();
        }

We can also create another extension to Activator Type to actually call the Constructor, like this:-

public static T CreateInstance<T>(this Activator activator, params object[] args) where T : class
        {
            return activator(args) as T;
        }

Here is how to call the above set of methods to create an instance of PartyWear Shirt:- 

var type = typeof (PartyWear);
var activator = type.GetActivator();

var shirt = activator.CreateInstance<Shirt>(Color.Blue, "Blackberry");

Now, let’s run the litmus test.  

We will make two factories one with System Activator and the other one with Expression Tree Activator and see the difference:- 

 

Well, well, well, you can see the difference.

The one with expression trees took less than half a second to make a million Tee Shirts where as system Activator took a whopping 4.7 seconds.

So that’s it Folks, Download the code attached and play with it.

Happy Programming!!! 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here