Using reflection to create a factory class for dynamic method invocation using templates.

Using reflection to create a factory class for dynamic method invocation using templates.

My group is using entity framework and we are trying to decouple ourselves from our legacy framework which returns tightly bound data contracts to our customers.   We use extension methods to convert entities into data contracts.  This is actually more complicated than it sounds because we also have a concept of a business entity which is embedded into our data contracts.  Neither of them implements interfaces so converting from one to the other and back requires a series of loops, and logic switches.

Additionally we use classes called repositories in our data access layer which call entity framework and then map from entity framework entities to data contracts and business entities via extension methods.  

Anyway here is the problem.

  • Our entity repositories are tightly coupled to data contracts and entities and only returns data contracts.
  • Our data contracts and business entities are tightly coupled and don’t return interfaces.
  • We already have a great deal of extension methods that we want to reuse.

Here is the proposal.

  •  I want to create a factory in between entity repositories and the mapper classes so we can decouple our entity repositories from our data contracts and business entities.
  • I want to reuse the existing extension methods.
  • I want to write new mapper classes targeted at specific contracts which are not extension methods.
  • I want to account for overloaded methods.

 I also want the factory method to be as generic and flexible as possible, I don’t want the factory to know about mappers and entities and return types.   I decided to use Reflection but in a very optimized way so that I can maintain good performance.   If you want to know more about performance pitfalls of applications and reflection, there is a very good article by Joel Pobar in msdn magazine, you can read it here:  http://msdn.microsoft.com/en-us/magazine/cc163759.aspx

Approach A.

First the factory method to reuse the data extensions.  Since the legacy EF mapper class is a class of extension methods with an overloaded TODC() method, there is no way of passing in the method to invoke so I have to check the input and output type of the method to see if it matches the input and output type of the contracts.  Let’s create the method signature of my factory class.

public class EntityFactory

{  

public OutputType Create<OutputType, InputType>(InputType entity, Type mapperTemplate) where OutputType : class

{}   

}

OK fair enough, I have a generic output type, and input type, a mapper template type and some constraints.  NOTE:  mapperTemplate is the static extension class with the extension methods that I want to reuse.

Using reflection I will find the methods in the mapper template class and then check the return type and the input parameters.   I will need to use reflection’s  MemberInfo to do this. As you can see below,  once I find the method I invoke it and return the result.   This works and is optimized but not as optimized as it could be due to the fact that I am reusing an existing extension method class. 

NOTE:  Stay with me if this seems messy; it gets cleaner later on in the post.

public OutputType Create<OutputType, InputType>(InputType entity, Type mapperTemplate) where OutputType : class

      {

         Type[] inputTypes = new Type[1] { typeof(InputType) };

         foreach (MemberInfo mi in mapperTemplate.GetMethods())

         {

            if (((MethodInfo)mi).ReturnType == typeof(OutputType))

            {

               MethodInfo method = mapperTemplate.GetMethod(((MethodInfo)mi).Name, inputTypes);

               if (method != null)

               {

                  return method.Invoke(null, new object[] { entity }) as OutputType;

               }

            }

         }

         return null;

      }

You’ll notice that after I get the matching return type I attempt to retrieve the method by name and by passing in the method parameter types.  If the method is returned then I invoke the method, otherwise I try again.   If you don’t pass in the method parameter types you may get back an overloaded method by the same name and the attempt to invoke will cause reflection to throw an Ambiguous Match Exception

Here is how I call the method above from my unit tests.

DAL is the namespace for Data Access Layer.

DC is the namespace for my Data Contracts.

List<MyItem> myItems = new List<MyItem>();

  var results = this.repository.SearchResults(criteria);

  foreach (var item in results)

 {

   myItems.Add(entityFactory.Create<DC::Item, DAL::ItemTypeTemplate>(results, typeof(DAL.EFExtensionMappers))

    );

   }

Approach B.

Next I want my factory method to use new mapper template classes.  Since this class will have unique method names, I can just pass the method name and the template class and call invoke.  Pretty simple and very optimized.

public OutputType Create<OutputType, InputType>(InputType entity, Type mapperTemplate, string methodName) where OutputType : class

      {

         Type[] inputTypes = new Type[1] { typeof(InputType) };

         MethodInfo mi = mapperTemplate.GetMethod(methodName, inputTypes);

         return mi.Invoke(null, new object[] { entity }) as OutputType;

      }

Notice I pass in the input parameter types again to avoid the Ambiguous Match Exception caused by overloaded methods.

Here is how I call the method above from my unit tests.

DAL is the namespace for Data Access Layer.

DC is the namespace for my Data Contracts.

List<MyItem> myItems = new List<MyItem>();

var results = this.repository.SearchResults(criteria);

  foreach (var item in results)

  {

    myItems.Add(entityFactory.Create<DC::Item, DAL::ItemTypeTemplate>(results, typeof(DAL.NewtemMappers), “GetItems”)

         );

   }

Up to this point I have only been able to pass to methods with one argument.  Now I want to pass to methods with multiple arguments.   Here is how I handle this one.

public OutputType Create<OutputType>(Type[] inputTypes, object[] arguments, Type mapperTemplate, string methodName) where OutputType : class

      {

         MethodInfo mi = mapperTemplate.GetMethod(methodName, inputTypes);

         return mi.Invoke(null, arguments) as OutputType;

      }

Finally, here is how I call this method.

List<MyItem> myItems = new List<MyItem>();

var args = new object[] { results, “test” };

Type[] parms = new Type[2] { typeof(DAL::AgreementTypeTemplate), typeof(String) };

foreach (var item in results)

{

   myItems.Add(entityFactory.Create<DC:: Item >(parms, args, typeof(DAL. ItemTypeTemplate), “GetItems”)

);

 }

I hope you have found this type of dynamic factory helpful.

Cheers!

Advertisements

~ by CC on March 6, 2010.

One Response to “Using reflection to create a factory class for dynamic method invocation using templates.”

  1. Chris,
    Fascinating insights… The secret is in the input parameters… trust me…
    Steve Aloia, Ph.D.

    (The degree has nothing to do with my insights … per se… But in an obtuse way it does)… Enjoyed the blog….

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: