Click here to Skip to main content
Click here to Skip to main content

Reflection is Slow or Fast? A Practical Demo

, 5 Nov 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
The article demonstrates how Reflection APIs behaves in real time development and also gives you few ways to improve its performance.

Introduction

After speaking few notes on Reflection.Emit, I thought of checking how reflection works in real world scenarios. After I Googled, I saw few great articles in this regard and each of them spoke about Reflection being slow. Many of you like me might have heard, calling reflection APIs from your code is always slower than that of calling it directly. Well, it is right. Some of the major Reflection methods like GetXXX (of MethodInfo, PropertyInfo, FieldInfo, etc.) are say 100 times slower than that of calling a Method, Property or Fields directly. In this post, I will try to cover some of the major portions of Reflection which are slower like hell than that of normal method call and also try to solve the same.

What is Reflection for?

As I have already told you about Reflection and Code Emit and also how to build your Lamda Expression Tree, it is good to know where you would like to use Reflection. Yes... Reflection is made truly late bound approach to browse through the object hierarchy or to call methods inside the object. So if you do not know much about your object hierarchy or you have somehow found an assembly external to your application and you need to parse through the object and call its methods say, then Reflection would be the right choice for you.

So basically Reflection allows you to create plugin type of applications where you define an Interface and publish the same for your application and let others create those plugins for you to seamlessly add to your application. Fine. Then what it isn't for?

Yes, basically few people try to work everything based on Reflection. Using reflection unnecessarily will make your application very costly. Say for instance,

ConstructorInfo cinfo= typeof(MyType).GetConstructor(
                     new Type[] { typeof(int), typeof(string) });
object createdObject = cinfo.Invoke(new object[] { 10, "Abhishek" });
MyType xyz = createdObject as MyType;

Or say using:

MyType typ = Activator.CreateInstance<MyType>(); 

Silly huh..

I saw few people doing this. They try to use everything using Reflection, maybe they love Reflection too much, or they have already created a Reflection engine right and do not want to mix up unknown types with known ones. Maybe they would make their code clear by calling the known types to the same module that is built up for dealing with unknown types.

These things go really worse when you do these reflection calls in a loop. Say for instance, you are about to set 100s of members of an object at runtime and use say PropertyInfo to deal with these 100 setters. Yes, the code will look very simple but at a performance cost.

Type.InvokeMember is often very slow as well as Activator.CreateInstance, when there are large number of Members in a type, of there are a large number of Types in an assembly. Yes, going truly late bound with these will make your application real slow.

Where Should You Avoid Reflection

This is the general question for everyone. Reflection works very well when you know the object. The more you know about the object, the more you can avoid searching the object hierarchy. One of the costliest methods I have found is GetCustomAttributes, where you are trying to find an attribute from a type, whether it is added or not to do something with the types. If you don't know where the Custom attributes to be set are or say you have AttributeTargets.All set to the attribute and you use:

myassembly.GetCustomAttributes(true) 

The additional parameter true means it will go through all the Types, its methods, its properties and try to find your attribute. Hence it's a call to traverse the whole object hierarchy. Yes, this is horribly costly. You must avoid these calls. Let me list some of the costly methods on Reflection:

  • GetCustomAttributes
  • GetXX ( PropertyInfo, MethodInfo, EventInfo, FieldInfo etc)
  • Type.InvokeMember (when Type is very big)
  • Activator.CreateInstance

There are others too. But you should always try to avoid these methods call in a loop.

Reflection with ASP.NET Websites

When it comes with the notion of ASP.NET websites, we always think of dealing with performance and throughput. For ASP.NET sites, it is better to avoid excessive usage of Reflection, may be when you use Reflection for every call to invoke a member which is plugged in to your application, it would make your application work slower and slower when you have thousands of calls to your application. This is the problem with DasBlog which actually have used Reflection to deal with each blog posted. Hanselman pointed out the issue for them, as it tries to find out each member using Reflection. The performance of the site increased 100 times just by changing these things.

If your Web application needs to perform well in stressed conditions, I should say you should think twice before using Reflection at your end. Rather it would be lightening fast if you didn't use Reflection to deal with every step.

How Slow Is Reflection?

Yes, now it's time to deal with Reflection against real time data. As Reflection is truly late bound approach to work with your types, the more Types you have for your single assembly the more slow you go on. Let me try to demonstrate to you how slow the performance is by taking an example of a large DLL (with 100s of types associated with it) and try to invoke a member on it using Reflection and without it and measure the performance boost you have.

Eric Gunnerson also employed a lot of effort around measuring the few methods himself. In his article (sorry it isn't available), he demonstrated based on his 100,000 call to a single method in .NET framework 1.1 gives him results like:

reflection.JPG So according to him, Type.InvokeMember and DynamicMethod.Invoke takes the longest time to run. MethodBase.Invoke (or MethodInfo.Invoke) is half in performance, DynamicMethod.Delegate will take even lesser time, next is normal delegate call, finally the interface call and IL based instructions. Fairly smart enough? Probably, but let's build our own application to demonstrate these scenarios.

Let me take an example of a simple class (I call it DummyClass) which has only 1 method in it named CallMe inside a DummyNamespace on a large assembly with 547 Types. So the class looks like:

namespace DummyNamespace
{
    public class DummyClass
    {
        public void CallMe(int x)
        {
           x = x + 10;
           return;
        }
    }
}

Looks simple, huh.. Well, let's create a consumer class to check how it performs in stressed situations. I will create objects of DummyClass in a loop and call CallMe with random values in both using Reflection API and normally. To do this, I create a class ReflectionCalculator with few methods.

public class ReflectionCalculator
{
    private Assembly _currentassembly;
    public Assembly CurrentAssembly
    {
        get
        {
            if (this._currentassembly == null)
                this._currentassembly = Assembly.LoadFrom("PredictADry.BizLogic.dll");
            return this._currentassembly;
        }
    }
    public void ReflectionBasedCall(int value)
    {
        Type dummyclass = this.CurrentAssembly.GetType("DummyNamespace.DummyClass",
                                                        true, true);
        MethodInfo dummyMethod = dummyclass.GetMethod("CallMe", BindingFlags.Instance | 
                         BindingFlags.Public, null, new Type[] { typeof(int) }, null);
        object dummyObject = Activator.CreateInstance(dummyclass);
        dummyMethod.Invoke(dummyObject, new object[] { value });
    }
        
    public void NormalCall(int value)
    {
        DummyClass oclass = new DummyClass();
        oclass.CallMe(value);

    }
}

So if you look into these two calls, viz ReflectionBasedCall and NormalCall, you could see, definitely both are doing the same thing. I have placed an Assembly object outside so that I could check only the logic to call a method. The Reflection approach needs to first Get a Type using Assembly.GetType, which eventually searches the entire object hierarchy and then GetMethod, which finds on the Type. Hence the bigger the size of the assembly, the slower these work. Finally the Activator.CreateInstance which actually create the instance of the object. While the other is doing the same thing normally. Now if say I call both the methods 100000 times using this code and print out the time in milliseconds, it will look like:

static void Main(string[] args)
{
    DateTime currentTime;
    ReflectionCalculator calculator = new ReflectionCalculator();
    Console.WriteLine("Time Now : {0}", DateTime.Now.ToLocalTime());
    currentTime = DateTime.Now;

    for (int i = 0; i < 100000; i++)
    {
        calculator.NormalCall(i);
    }

    TimeSpan spannedtime = DateTime.Now.Subtract(currentTime);
    Console.WriteLine("Time Elapsed for Normal call : {0}", 
                             spannedtime.TotalMilliseconds);

    currentTime = DateTime.Now;
    for (int i = 0; i < 100000; i++)
    {
        calculator.ReflectionBasedCall(i);
    }
    spannedtime = DateTime.Now.Subtract(currentTime);
    Console.WriteLine("Time Elapsed for Reflection call : {0}", 
                            spannedtime.TotalMilliseconds);

    Console.ReadLine();
}

Hence the output will be:

reflectiondemo.JPG

So you can definitely get the idea how slow Reflection works in comparison to normal calls. Reflection approach is almost 30 times slower than that of normal call.

Caching Objects to Relax

Well, let's make the code more friendly to allow caching of objects for each call. So let's create a few properties to cache the objects for Reflection call and see how it works:

private Type dummyType;
public Type DummyType
{
    get 
    { 
        this.dummyType = this.dummyType ?? this.CurrentAssembly.GetType(
                                  "DummyNamespace.DummyClass", true, true); 
        return this.dummyType; 
    }
}
private MethodInfo method;
public MethodInfo Method
{
    get
    {
        this.method = this.method ?? this.DummyType.GetMethod("CallMe", 
                        BindingFlags.Instance | 
                        BindingFlags.Public, null, new Type[] { typeof(int) }, null);
        return this.method;
    }
}
private object dummyObject;
public object DummyObject
{
    get
    {
        if (this.dummyObject == null)
        {
            dummyObject = Activator.CreateInstance(this.DummyType);
        }
        return dummyObject;
    }
}
//More relaxed with caching of objects
public void ReflectionBasedCall(int value)
{
    this.Method.Invoke(this.DummyObject, new object[] { value });
}
public DummyClass MyClass { get; set; }
public void NormalCall(int value)
{
    this.MyClass = this.MyClass ?? new DummyClass();
    this.MyClass.CallMe(20);

}

So here, we cache each objects in its respective properties. So, it might relax our head a bit, but mind that this could not be the situation that you can have the same method every time. But to see how fast method Invoke works, let's run the code.

reflectiondemo1.JPG

So the time consumed abruptly decreased due to caching applied on it. So basically most of the time was taken by GetType and GetMethod and even with Activator.CreateInstance. But if you see the result, it is still 15 times the normal call.

Using an Interface

Interface works great in these situations. Let's take an Interface which is present in both the DLLs where the DummyClass actually implements the interface IDummy. OMG, interface works so well in these situations. If you have everything cached, it works the same like normal calling instructions.

private IDummy dummyObject;
public IDummy DummyObject
{
    get
    {
        if (this.dummyObject == null)
        {
            dummyObject = Activator.CreateInstance(this.DummyType) as IDummy;
        }
        return dummyObject;
    }
}
public void ReflectionBasedCall(int value)
{
    //this.Method.Invoke(this.DummyObject, new object[] { value });
    this.DummyObject.CallMe(value);
}

Hence the output is:

reflectiondemo21.JPG

You must be amazed to see this. Yes, it actually works better in this situation than that of normal IL instructions.

But no.. It's actually not. Basically calling a lightweight interface is better than calling a concrete object from architectural point of view. If you make the caching of IDummy for a moment and compare, you will see the difference. Holding Cached object and calling through its interface is better in performance than that of the normal calls. So let's change our code a bit and see:

private IDummy dummyObject;
public IDummy DummyObject
{
    get
    {
        if (this.dummyObject == null)
        {
            dummyObject = Activator.CreateInstance(this.DummyType) as IDummy;
        }
        return dummyObject;
    }
}
public void ReflectionBasedCall(int value)
{
    //this.Method.Invoke(this.DummyObject, new object[] { value });
    this.DummyObject.CallMe(value);
}

Hence, if you create both objects each time, the performance will be:

reflectiondemo31.JPG

Yes rightly so, Interface will not work better than raw IL instructions. But is it possible to have Interface for everything we call? You are right, it would put a lot of effort if you need to have interface for every single Reflection call. So probably it's time to think of something else.

Using Dynamically Created Delegates for Each Method

Well another or probably best approach I found is the use of dynamically created delegates based on signature of MethodInfo, PropertyInfo objects. Using Dynamic flexibility of C# language or creating dynamic delegate at runtime will make the Reflection code very fast.

Basically the idea is to build Generic delegates for each type of MethodInfo we need to call and eventually store the same into some in memory cache. This way, you just need to build some Action<> or Func<> delegates for your calls (based on the signature) and on every call to them, you can maintain a list where you store each delegate with the MethodInfo. Hence for the next time, when you require to invoke the same method, you could use the delegate directly.

To do this, I have used System.Linq.Expressions. If you are new to Dynamic feature using Expression Tree, you can try my post to grab the concept. I have used Expression as it seems better for me, but you could also use System.Reflection.Emit to build these call wrappers.
To use this, I have created a few extension methods for properties, methods, etc. Let's take the example of MethodInfo in our case.

public static Action<object, T> CallMethod<T>(this MethodInfo methodInfo)
{
    if (!methodInfo.IsPublic) return null;

    ParameterExpression returnParameter = Expression.Parameter(typeof(object), "method");
    ParameterExpression valueArgument = Expression.Parameter(typeof(T), "argument");

    MethodCallExpression methodcaller = Expression.Call(
                                    Expression.ConvertChecked(returnParameter, 
                                    methodInfo.DeclaringType),
                                    methodInfo,
                                    Expression.Convert(valueArgument, typeof(T)));
    return Expression.Lambda<Action<object, T>>(methodcaller, 
                                        returnParameter, valueArgument).Compile();
}

So eventually, I am using this Lambda expression to build an Action<object,T> where object represents the instance of the class for which we are going to execute the method and T represents the Type argument in the argument list.

If you see the code above cautiously, you could understand that I am building a lambda like:

(x, y) => return x.[method](y)

So using the caching as well here, let's dynamically build our delegate object using the code:

# region Cache
private MethodInfo methodInfo;
public MethodInfo CachedMethodInfo
{
    get
    {
        this.methodInfo = this.methodInfo ?? this.GetMethodInfo();
        return this.methodInfo;
    }
}

private MethodInfo GetMethodInfo()
{
    Type dummyclass = this.CurrentAssembly.GetType("DummyNamespace.DummyClass", 
                                                    true, true);
    MethodInfo dummyMethod = dummyclass.GetMethod("CallMe", BindingFlags.Instance | 
                    BindingFlags.Public, null, new Type[] { typeof(int) }, null);

    return dummyMethod;
}
private object instance;
public object Instance
{
    get
    {
        this.instance = this.instance ?? Activator.CreateInstance(typeof(DummyClass));
        return this.instance;
    }
}
private Action<object, int> _methodcallDelegate = null;
public Action<object, int> MethodCallDelegate
{
    get
    {
        this._methodcallDelegate = this._methodcallDelegate ?? 
              this.CachedMethodInfo.CallMethod<int>();

        return this._methodcallDelegate;
    }
}

# endregion

public void CacheBasedDelegateCall(int value)
{
    this.MethodCallDelegate(this.Instance, value);
}

So basically, I have built a delegate object with MethodCallDelegate and also cached the same for every call of the method. The MethodCallDelegate actually invokes the extension method CallMethod from CachedMethodInfo object and stores it into a variable.

Note: In your real time application, when you require to create a large number of Reflection calls, cache MethodDelegate in a collection with MethodInfo objects, so that you could try to find the same from the collection instead of creating the Dynamic method each time you call.

Now to demonstrate this, let's put another section in our program to call this CacheBasedDelegateCall. Hence the output will look like:

reflectiondemo41.JPG

OMG, it works great with this approach. Yes, if you can leverage out the time taken to dynamically compile the application, then the application will work as fast as before.

That's it.

Conclusion

Hence I think I have made things clear a bit and I hope you have enjoyed reading it. Thank you and post your views in this regard.

Happy programming!

References

History

  • Initial draft - November 6th 2010

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Abhishek Sur
Architect
India India
Did you like his post?
 
Oh, lets go a bit further to know him better.
Visit his Website : www.abhisheksur.com to know more about Abhishek.
 
Abhishek also authored a book on .NET 4.5 Features and recommends you to read it, you will learn a lot from it.
http://bit.ly/EXPERTCookBook
 
Basically he is from India, who loves to explore the .NET world. He loves to code and in his leisure you always find him talking about technical stuffs.
 
Presently he is working in WPF, a new foundation to UI development, but mostly he likes to work on architecture and business classes. ASP.NET is one of his strength as well.
Have any problem? Write to him in his Forum.
 
You can also mail him directly to abhi2434@yahoo.com
 
Want a Coder like him for your project?
Drop him a mail to contact@abhisheksur.com
 
Visit His Blog

Dotnet Tricks and Tips



Dont forget to vote or share your comments about his Writing
Follow on   Twitter   Google+

Comments and Discussions

 
GeneralMy vote of 5 PinmemberEdo Tzumer5-Nov-12 20:14 
GeneralMy vote of 5 PinmemberakramKamal23-Oct-12 10:08 
GeneralMy vote of 5 PinmemberSunKwon7-Aug-12 4:08 
GeneralMy vote of 5 Pinmemberjim lahey7-Sep-11 0:52 
GeneralMy vote of 5 PinmemberMichał Zalewski8-May-11 9:53 
GeneralVery Nice 5 from me PinmemberGandalf - The White20-Dec-10 20:30 
GeneralRe: Very Nice 5 from me PinmvpAbhishek Sur20-Dec-10 22:35 
Generalthis is really nice PinmemberPranay Rana15-Dec-10 21:14 
GeneralRe: this is really nice PinmvpAbhishek Sur18-Dec-10 6:18 
GeneralPerformance measurement suggestion PinmemberVimvq198714-Dec-10 0:35 
GeneralRe: Performance measurement suggestion PinmvpAbhishek Sur18-Dec-10 6:19 
GeneralMy vote of 5 PinmemberHiren Solanki13-Dec-10 23:01 
GeneralRe: My vote of 5 PinmvpAbhishek Sur18-Dec-10 6:19 
GeneralMy vote of 5 PinmemberRaviRanjankr13-Dec-10 20:13 
GeneralRe: My vote of 5 PinmvpAbhishek Sur18-Dec-10 6:19 
GeneralNice one PinmentorBrij13-Dec-10 10:20 
GeneralRe: Nice one PinmvpAbhishek Sur18-Dec-10 6:20 
GeneralGr8 PinmvpMd. Marufuzzaman13-Dec-10 3:47 
GeneralRe: Gr8 PinmvpAbhishek Sur18-Dec-10 6:20 
GeneralMy vote of 5 Pinmemberbruno.mmonteiro12-Nov-10 4:03 
GeneralRe: My vote of 5 PinmvpAbhishek Sur18-Dec-10 6:20 
GeneralArticle Incomplete PinmemberStefan Popov9-Nov-10 4:52 
GeneralRe: Article Incomplete PinmvpAbhishek Sur9-Nov-10 22:37 
GeneralMy vote of 5 Pinmemberfarproc20009-Nov-10 4:50 
GeneralRe: My vote of 5 PinmvpAbhishek Sur18-Dec-10 6:22 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 5 Nov 2010
Article Copyright 2010 by Abhishek Sur
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid