Click here to Skip to main content
15,879,535 members
Articles / Programming Languages / C# 4.0

Factory Method Pattern With Expression Trees using C#

Rate me:
Please Sign up or sign in to vote.
4.47/5 (7 votes)
13 May 2012CPOL3 min read 23.8K   5   22   6
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:- 

Image 1

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

C#
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:- 

C#
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. 

C#
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.

C#
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:- 

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

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

C#
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:-

C#
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:- 

C#
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:- 

 Image 2

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
India India
Lead Developer, working on .net platform for over 6.5 years with specialization in writing Telecom Software.

Have working experience in writing Entity Services using Domain Driven Design and RAD design paradigms.

A Microsoft Certified Professional Developer on .net Framework 3.5...

A programmer at heart, Love to spend time watching sci-fi movies, reading new technologies, and helping my community with whatever skill-set and knowledge i possess.

Comments and Discussions

 
GeneralMy vote of 3 Pin
Klaus Luedenscheidt14-May-12 19:02
Klaus Luedenscheidt14-May-12 19:02 
GeneralRe: My vote of 3 Pin
BuggyCoder14-May-12 20:15
BuggyCoder14-May-12 20:15 
QuestionHelper methods... Pin
Paulo Zemek14-May-12 5:05
mvaPaulo Zemek14-May-12 5:05 
AnswerRe: Helper methods... Pin
BuggyCoder14-May-12 8:34
BuggyCoder14-May-12 8:34 
QuestionThere are other more elaborate articles around on this topic Pin
Andreas Gieriet13-May-12 23:38
professionalAndreas Gieriet13-May-12 23:38 
AnswerRe: There are other more elaborate articles around on this topic Pin
BuggyCoder14-May-12 0:08
BuggyCoder14-May-12 0:08 
Hi Andi,

You know, i just tried to compare system activator with expression trees based Custom Activator.

The problem domain i am trying to focus here is more specific to object creation using Factory class and various ways to do the same.

The one that you referred, has a larger scope as it tells you how to go about creating your own custom IoC framework.

Object Creation is a subset of that article, whereas i tried to focus on the area of object creation more closely....

Hope i am clear on my effort here...
Thanks Smile | :)
BR,
BuggyCoder

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.