Generic Method Calls Using Expression Trees / Method Caching

The other day I wrote a bit of reflection inside an ASP .NET custom ModelBinder class to call a generic method, and my work colleague asked, isn’t that going to be slow.

I was like yeah but not that bad, besides if it proves to be a problem we can always speed it up using method caching and Expression Trees.

He then asked to see an example of that as he had not done too much with Expression Trees, I said sure I would knock one up for him.

The idea is a fairly simply one, we can to call a method, I was using Reflection which takes the Reflection hit every time, so what we need is to build up a Dynamic Delegate which we can store and which we can then call each time which will be lightning quick when compared to using Reflection, as all we are doing is calling a Delegate.

Enter ExpressionTrees.

Suppose this is my method that I want to call

//Will call this method via ExpressionTree
private T GetSomething<T>(string data)
{
    return (T)Activator.CreateInstance(typeof(T));
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

You can see that this method is generic and takes a string as a parameter. So what would an expression tree builder method look like, and what it would it return. Well it would look like this, and would return a Func delegate which we could cache somewhere, and call next time, which as I say would be very fast, as we are not doing any Reflection any more, we basically take the hit one when we 1st create the Func delegate.

//create delegate using Expression Trees
private static Func<Object, P1, T> ReflectGenericFunction<P1, T>(
    Type[] genericParams, Type objType, String methodName)
{
    ParameterExpression param = 
        Expression.Parameter(typeof(Object), "object");
    ParameterExpression param1 = 
        Expression.Parameter(typeof(P1), "paramP1");
    Expression convertedParam = 
        Expression.Convert(param, objType);
    Expression methodCall = 
        Expression.Call(convertedParam, methodName, genericParams, param1);
    LambdaExpression lambda = 
        Expression.Lambda(methodCall, param, param1);
    Expression<Func<Object, P1, T>> dynamicSetterExpression = 
        (Expression<Func<Object, P1, T>>)lambda;
    return dynamicSetterExpression.Compile();
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

And here is how we might call this method to get a Func delegate we could cache

If we know the correct generic values for the ReflectGenericFunction we can simply do this:

Type[] genericArgs = new Type[] { typeof(Person) };

//If we know the correct generic types can simply do this
Func<Object, String, Person> func = 
    ReflectGenericFunction<String, Person>(
        genericArgs, typeof(Program), "GetSomething");
var x = func(this,"Same");

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

If we need to dynamically create the types for the ReflectGenericFunction we can simply do this:

Type[] genericArgs = new Type[] { typeof(Person) };

///If we DO NOT know the correct generic types can simply do this
MethodInfo method = this.GetType().GetMethod("ReflectGenericFunction", 
    BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance);
method = method.MakeGenericMethod(new Type[] { 
    typeof(String), typeof(Person) });

Func<Object, String, Person> funcReflected = 
    (Func<Object, String, Person>)method.Invoke(
        this, new Object[] { genericArgs, 
        typeof(Program), "GetSomething" });

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

NOTE : The same thing can obviously be done using Delegate.CreateDelegate(..) but I thought this was interesting and I had to do it for my work collegue so thought I would just show you how.

Here is what you would do using Delegate.CreateDelegate

Declare a delegate type

public delegate object GetSomethingDelegate(string json);
Now create a method that will dynamically create the delegates
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

private GetSomethingDelegate GetSomethingDelegateType(Type modelType, object instance)
{
    MethodInfo method = this.GetType().GetMethod("GetSomething", 
        BindingFlags.NonPublic | BindingFlags.Instance);
    method = method.MakeGenericMethod(new Type[] { modelType });
    return (GetSomethingDelegate)Delegate.CreateDelegate(
        typeof(GetSomethingDelegate), instance, method);
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

And finally call the delegate creation method

GetSomethingDelegate funcDel = GetSomethingDelegateType(typeof(Person), this);
var x3 = funcReflected(this, "Using Delegate.CreateDelegate");
Console.WriteLine(x3.Id);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

As always here is a small demo project :

http://dl.dropbox.com/u/2600965/Blogposts/2011/08/DynamicMethodCachingUsingExpressionTrees.zip

About these ads

15 thoughts on “Generic Method Calls Using Expression Trees / Method Caching

  1. Hey Sasha,

    I don’t understand your GetSomething function — it doesn’t use the parameter named data at all. What am I missing?

    Thanks in advance,
    Robert
    “Lasting peace & happiness for *ALL* human beings!”

    • sacha says:

      That is not the point, was showing you how to call the method, not the methods code, the method code is not important in this case

  2. Neil Mosafi says:

    Nice post! I agree with Robert, the example you gave was unfortunate as the method being called used Reflection (which is misleading) and ignored a parameter. Would have better to have put a more simple method on there which just returned a value.

    Still, nice.

  3. Charles says:

    Thanx for sharing I actually used the same technique in an implementation of the visitor pattern to remove the visitor dependency from the visited objects without the performance hit introduced by reflection.

  4. Mahadesh says:

    Thanks for Sharing this nice article.
    I am trying out the same functionality using WCF. Since in WCF we cannot use Generics , I am using Reflection . I am using Expressions to build the Lambdas as you illustrated. But when I use the build Lambda in extension method where(). It does not work .

    Since my method looks like :

    TEntity Fetch(TEntity entity) ,

    TEntity is the generic Entity time which all the Entity types i use will extend . Basically I have implemented Inheritance instead of generic .

    On the Client Side I can pass the Real Entity and it would work since ,

    RealEntity : TEntity

    This solution works well when i don’t need a Lambda say
    GetAll() Method where i don’t have any criteria . I pull all records .

    But when I need a criteria I build a Lambda , problem is the return type of the WCF method is Generic(TEntity) but the Lambda which is built at runtime is Non Generic (RealEntity) . So I get a Typecast Issue .

    Please help.

    • sacha says:

      I do not think I would make the method return a generic TEntity, but would rather rely on some base entity type, and would use the knowntypeattribute to allow any known type to be serialized in place of the base type. That way your Expression tree could always just return the base type, and the WCF client would need a cast but that is not such a big deal in my opinion

  5. Mahadesh says:

    Thanks Sacha ,

    Can you give me few more details . I am already using the KnownType Attribute as you pointed out .

    Please find some code :

    [KnownType(typeof(Company))]
    [Serializable()]
    [DataContractAttribute(IsReference = true)]
    public class TEntity : EntityObject
    {
    // No functionality is implemeneted here just a dummy class
    }

    [EdmEntityTypeAttribute(NamespaceName=”MCSModel”, Name=”Company”)]
    [Serializable()]
    [DataContractAttribute(IsReference=true)]
    public partial class Company : TEntity
    {
    }

    This is how my method signature looks :
    public IEnumerable First(TEntity entity)

    I construct the Lambda as shown below :

    var param = Expression.Parameter(typEntity, “p”);
    var len = Expression.PropertyOrField(param, “Name”);
    var body = Expression.Equal(len, Expression.Constant(“”,typeof(string)));

    I compile it .

    dynamic a1 = lambda.Compile();

    and pass to the below method ,

    var o2 = _objectSet.Where(a);

    The Issue is that object a in above expression is a lambda expression which is at runtime the type pf table but it clashes with the Generic Return Type which I return .

    I understand that you advised not to return Generic return Type Then how can i do this . Please Help .

    If you would like to know how I construct the _ObjectSet , you can find the method here .

    public object Reflection(TEntity entity)
    {

    MCSEntities context = new MCSEntities();

    Type[] typeArgs = { ObjectContext.GetObjectType(entity.GetType()) };
    Type typObjectContext = context.GetType();
    Type[] NoParams = { };
    MethodInfo meth = typObjectContext.GetMethod(“CreateObjectSet”, NoParams);

    MethodInfo methGeneric = meth.MakeGenericMethod(typeArgs);

    return methGeneric.Invoke(context, null);
    }

    }

    Please let me know if you need any further details .

    Thanks ,

    Mahadesh

  6. Mahadesh says:

    Hi Sacha ,
    In Short my requirement is to execute a method like ,

    private T GetSpecificThing(string data)
    {
    return (T)Activator.CreateInstance(typeof(T).Where (x => x.Name = “John”);
    }

    where Name is a Field of Type T .

    Please let me know how to get this done .

    Thanks ,
    Mahadesh

  7. Ranjith Kumar says:

    Sacha ,

    This is exactly what I need as Well.

    It would Help if you could provide a sample code of how to execute method which a conditional Lambda .

    Mahadesh ,

    Plz let know if you Solve the Issue .

    Waiting …..
    Ranjith

  8. Ian says:

    I did something similar to this the other day only I extended the idea a bit more. I extended the idea to property accessors and made it recursive. So you can do “PropertyA.PropertyB.PropertyC”.

    You mentioned that you could also do CreateDelegate but the downside of that is that you have to call create delegate for each object and store the delegate for each object you want to access. With this method you create the accessor once and just use it.

    After creation the performance is roughly 4-5% slower, which compared to reflection is awesome (I’ve seen 10x and slower from reflection).

    • sacha says:

      Neat. Care to show your recursive code as a posted comment/link here for others to look at.

      Also on the idea of “PropertyA.PropertyB.PropertyC”, a while back I created a chained property observer (bit of topic I know) which may be of interest to you : Chained Observer

  9. Ian says:

    I’m looking into seeing if I’m allowed to post it or write an code project article on it (I’m not sure its worth a full blown article but my boss liked that idea better).

    As for the chained observer that’s a really interesting idea. I ended up solving the problem in a different way by having the object implement an interface that defines a hierarchy and bubbles up the property changed even to a root object (I’m not sure its any better or worse because you end up in the same predicament in terms of LoD).

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