Want to show your appreciation? Please to my charity.

Friday, May 08, 2009

Strong Typed, High Performance Reflection with C# Delegate

Update: Open source project SharpCut delivers a less than 50K library which does what described here in one line plus much more. Check it out.

Content

  1. Inspiration: C#.Net Calling Grandparent's Virtual Method (base.base in C#)
  2. Prototype: Strong Typed, High Performance Reflection with C# Delegate (Part I) <= you are here
  3. Performance: Strong Typed, High Performance Reflection with C# Delegate (Part II)
  4. Library Usage: Strong Typed, High Performance Reflection with C# Delegate (Part III) 

The process of finding a solution for base.base.VirtualMethod() in C# inspired me to create utility/extension method for reflection. The goal was to use delegate instead of MethodInfo.Invoke or DynamicMethod.Invoke. Using the Invoke method requires boxing all value type to object, create an object array, unboxing before call the actual method, boxing/unboxing the return value if necessary and cast the return value to the excepted data type. Very involved indeed.

If the MethodInfo or DynamicMethod is reused to make the call, using Invoke method is costly and error prone. Can we create a Delegate object out of them so that it can be strong typed, and hopefully more efficient.

DynamicMethod class has overloaded methods named CreateDelegate. And Delegate class too has CreateDelegate methods that takes MethodInfo, so .Net framework does have the weapon we need.

Let's go step by step.

Utility method to create non-virtual invoke DynamicMethod from MethodInfo

Fist, extract the part that create the DynamicMethod in my last post and enhance it to work with any given MethodInfo object.

        public static DynamicMethod CreateNonVirtualDynamicMethod(this MethodInfo method)
        {
            int offset = (method.IsStatic ? 0 : 1);
            var parameters = method.GetParameters();
            int size = parameters.Length + offset;
            Type[] types = new Type[size];
            if (offset > 0) types[0] = method.DeclaringType;
            for (int i = offset; i < size; i++)
            {
                types[i] = parameters[i - offset].ParameterType;
            }

            DynamicMethod dynamicMethod = new DynamicMethod(
                "NonVirtualInvoker_" + method.Name, method.ReturnType, types, method.DeclaringType);
            ILGenerator il = dynamicMethod.GetILGenerator();
            for (int i = 0; i < types.Length; i++) il.Emit(OpCodes.Ldarg, i);
            il.EmitCall(OpCodes.Call, method, null);
            il.Emit(OpCodes.Ret);
            return dynamicMethod;
        }

With this tool, we can slim down our implementation of base.base in class C quite a bit.


    class C : B
    {
        private static readonly DynamicMethod baseBaseFoo;
        static C()
        {
            MethodInfo fooA = typeof(A).GetMethod("foo", BindingFlags.Public | BindingFlags.Instance);
            baseBaseFoo = fooA.CreateNonVirtualDynamicMethod();
        }
        public override string foo() { return (string)baseBaseFoo.Invoke(null, new object[] { this }); }
    }

Create Delegate from DynamicMethod

As we said in the beginning that the DynamicMethod.Invoke is verbose and and inefficient. The solution is to create a Delegate out of DynamicMethod and use the Delegate.  We can do it right inside the class C, and you can see that the call to the baseBaseFoo now is short, clean and strong typed. We'll discuss the performance benefit in next post.


    class C : B
    {
        private static readonly Func<A, string> baseBaseFoo;
        static C()
        {
            MethodInfo fooA = typeof(A).GetMethod("foo", BindingFlags.Public | BindingFlags.Instance);
            baseBaseFoo = 
                (Func<A, string>)fooA.CreateNonVirtualDynamicMethod()
                .CreateDelegate(typeof(Func<A, string>));
        }
        public override string foo() { return baseBaseFoo(this); }
    }

This is great with one downside is that we had to cast here and there when we create the Delegate. Can we extract this logic into a generic method so that in class C I can simply do this?

    baseBaseFoo = GetNonVirtualInvoker<Func<A, string>>(fooA);

My first attempt was not successful. See the code below


        public static TDelegate GetNonVirtualInvoker<TDelegate>(this MethodInfo method)
            where TDelegate : Delegate
        {
            var dynamicMethod = CreateNonVirtualDynamicMethod(method);
            return (TDelegate)dynamicMethod.CreateDelegate(typeof(TDelegate));
        }

It would be most ideal if this works so that the generic method only takes Delegate as type parameter. But the compiler give me a red line under the constrain type Delegate and complained that "Constraint cannot be special class 'System.Delegate'". Why Microsoft? Come and vote for the change here!

My second attempt is to use cast. But the compiler was still unhappy with error message: "Cannot cast expression of type 'System.Delegate' to 'TDelegate'".

        public static TDelegate GetNonVirtualInvoker<TDelegate>(this MethodInfo method)
        {
            var dynamicMethod = CreateNonVirtualDynamicMethod(method);
            return (TDelegate)dynamicMethod.CreateDelegate(typeof(TDelegate));
        }

This is very annoying. Is something wrong with the framework/language design? The workaround turn out to be very simply. Cast to object then back to TDelegate. (Update 5/15: actually there is a workaround to avoid double cast)

Finally the code below works:
        public static TDelegate GetNonVirtualInvoker<TDelegate>(this MethodInfo method)
        {
            var dynamicMethod = CreateNonVirtualDynamicMethod(method);
            return (TDelegate)(object)dynamicMethod.CreateDelegate(typeof(TDelegate));
        }

Thus the class C can be further simplified to:

    class C : B
    {
        private static readonly Func<A, string> baseBaseFoo;
        static C()
        {
            MethodInfo fooA = typeof(A).GetMethod("foo", BindingFlags.Public | BindingFlags.Instance);
            baseBaseFoo = fooA.GetNonVirtualInvoker<Func<A, string>>();
        }
        public override string foo() { return baseBaseFoo(this); }
    }

One stop shop extension method returns Delegate from type and method name

Now look at the goal set in the last post and repeated below. The class C must be further cut down to achieve the goal.

    class C : B
    {
        private static readonly Func<A, string> baseBaseFoo = 
            typeof(A).GetNonVirtualInvoker<Func<A, string>>("foo");
        public override string foo() { return baseBaseFoo(this); }
    }

Indeed, getting the MethodInfo object from a given type is never a one liner, it becomes verbose when method is overloaded thus parameters types matching is necessary. Things are getting more interesting now. Delegate has the precise information about the signature of method. Our utility method can be further enhanced to find the method from a given type with just a method name, because the parameter information can be found in the Delegate type.

        public static TDelegate GetNonVirtualMethod<TDelegate>(this Type type, string name)
        {
            Type delegateType = typeof(TDelegate);
            if (!typeof(MulticastDelegate).IsAssignableFrom(delegateType))
            {
                throw new InvalidOperationException(
                    "Expecting type parameter to be a Delegate type, but got " +
                    delegateType.FullName);
            }
            var invoke = delegateType.GetMethod("Invoke");
            ParameterInfo[] parameters = invoke.GetParameters();
            int size = parameters.Length - 1;
            Type[] types = new Type[size];
            for (int i = 0; i < size; i++)
            {
                types[i] = parameters[i + 1].ParameterType;
            }
            var method = type.GetMethod(name, 
                BindingFlags.Public | BindingFlags.NonPublic | 
                BindingFlags.Instance | BindingFlags.InvokeMethod, 
                null, types, null);
            if (method == null) return default(TDelegate);
            var dynamicMethod = CreateNonVirtualDynamicMethod(method);
            return (TDelegate)(object)dynamicMethod.CreateDelegate(delegateType);
        }

This extension method let you created a Delegate that can make non-virtual invocation to the named method of given type. The method parameters matches the signature of the Delegate. For example, instance method ClassA.Method1(string, int) matches Delegate(ClassA, string, int). The extension method started with making sure the type parameter is indeed a Delegate type, then retrieve the parameter types from the Delegate's Invoke method, then lookup the method in the given type, create dynamic method and finally create the Delegate.

Continue...

The complete code used in this blog can be found here. The code is the result of inception and prototype of the Common.Reflection. In next few posts, we'll implement formal extension methods with enhanced features and compare the performance between direct method call, reflection invoke and Delegate call.

22 comments:

Mithun Mithun said...



Given so much information in it. its very useful .perfect explanation about Dot net framework.Thanks for your valuable information. dot net training in velachery | dot net training in chennai

Pavithra M said...

It is really a great work and the way in which u r sharing the knowledge is excellent.
Thanks for helping me to understand basic concepts. As a beginner in Dot Net programming your post help me a lot.Thanks for your informative article. Dot Net Training in chennai | Dot Net Training in velachery

Kingsly David said...

Great post! Thanks for sharing with us.

Angularjs Training in Chennai | Web Designing Training in Chennai

sai said...

We are a group of volunteers and starting a new initiative in a community. Your blog provided us valuable information to work on.You have done a marvellous job!
Click here:
angularjs training in bangalore
Click here:
angularjs training in chennai

john jersy said...

Really great post, I simply unearthed your site and needed to say that I have truly appreciated perusing your blog entries.
Click here:
Microsoft azure training in velarchery
Click here:
Microsoft azure training in sollinganallur

ummayashri said...

This looks absolutely perfect. All these tiny details are made with lot of background knowledge. I like it a lot. 

Blueprism training in Chennai

Blueprism training in Bangalore

Blueprism training in Pune

Blueprism online training

Blueprism training in tambaram

johnsy sai said...

The knowledge of technology you have been sharing thorough this post is very much helpful to develop new idea. here by i also want to share this.
Devops training in sholinganallur

amala jst said...

A very nice guide. I will definitely follow these tips. Thank you for sharing such detailed article. I am learning a lot from you.

rpa training in electronic-city | rpa training in btm | rpa training in marathahalli | rpa training in pune

nivatha said...

Really great post, I simply unearthed your site and needed to say that I have truly appreciated perusing your blog entries. I want to say thanks for great sharing.
Data Science training in rajaji nagar | Data Science with Python training in chenni
Data Science training in electronic city | Data Science training in USA
Data science training in pune | Data science training in kalyan nagar

simbu said...

I really appreciate this post. I’ve been looking all over for this! Thank goodness I found it on Bing. You’ve made my day! Thx again!
java training in annanagar | java training in chennai

java training in chennai | java training in electronic city

thulasi ragini said...


Whoa! I’m enjoying the template/theme of this website. It’s simple, yet effective. A lot of times it’s very hard to get that “perfect balance” between superb usability and visual appeal. I must say you’ve done a very good job with this.

Selenium Interview Questions and Answers

Best Selenium Training in Chennai | Selenium Training Institute in Chennai | Besant Technologies

Selenium Training in Bangalore | Best Selenium Training in Bangalore

Free Selenium Tutorial |Selenium Webdriver Tutorial |For Beginners

Revathy A said...

I was looking for this certain information for a long time. Thank you and good luck.

angularjs Training in chennai
angularjs Training in chennai

angularjs-Training in tambaram

angularjs-Training in sholinganallur

angularjs-Training in velachery

Aruna Ram said...

Wonderful article! This is very easily understanding to me and also very impressed. Thanks to you for your excellent post.
Blue Prism Training in Bangalore
Blue Prism Institute in Bangalore
Blue Prism Training Institute in Bangalore
Blue Prism Course in Annanagar
Blue Prism Course in Adyar
Blue Prism Training in Ambattur

amsa leka said...

Thanks for such a great article here. I was searching for something like this for quite a long time and at last, I’ve found it on your blog. It was definitely interesting for me to read about their market situation nowadays.AngularJS Training in Chennai | Best AngularJS Training Institute in Chennai

kavinilavu G said...

Such a Great Article!! I learned something new from your blog. Amazing stuff. I would like to follow your blog frequently. Keep Rocking!!
Blue Prism training in chennai | Best Blue Prism Training Institute in Chennai

Rithi Rawat said...

Thankyou for providing the information, I am looking forward for more number of updates from you thank you

Check out :
top institutes for machine learning in chennai

machine learning with python course in Chennai

machine learning training in velachery


Robotic Process Automation Tutorial said...

Thank you so much for your information,its very useful and helful to me.Keep updating and sharing. Thank you.
RPA training in chennai | UiPath training in chennai

DJ PRASATH said...

Thanks for your post. This is excellent information. The list of your blogs is very helpful for those who want to learn, It is amazing!!! You have been helping many application.
best selenium training in chennai | best selenium training institute in chennai selenium training in chennai | best selenium training in chennai | selenium training in Velachery | selenium training in chennai omr | quora selenium training in chennai | selenium testing course fees | java and selenium training in chennai | best selenium training institute in chennai | best selenium training center in chennai

Roja Priya said...

Hi, Thanks a lot for your explanation which is really nice. I have read all your posts here. It is amazing!!!
Keeps the users interest in the website, and keep on sharing more, To know more about our service:
Please free to call us @ +91 9884412301 / 9600112302

Openstack course training in Chennai | best Openstack course in Chennai | best Openstack certification training in Chennai | Openstack certification course in Chennai | openstack training in chennai omr | openstack training in chennai velachery

Aruna Ram said...

Thank you for your efforts. This blog is very impressed to me and I got a lot of information to your post. Please keep it.
PHP Training in Bangalore
PHP Course in Bangalore
PHP Training in Annanagar
PHP Course in Anna Nagar
PHP Training in Tnagar
PHP Course in Tnagar
PHP Training in Omr
PHP Course in Omr

amsa leka said...

Wow!! Really a nice Article. Thank you so much for your efforts. Definitely, it will be helpful for others. I would like to follow your blog. Share more like this. Thanks Again.
iot training in Chennai | Best iot Training Institute in Chennai

cynthia williams said...

Wonderful post. Thanks for taking time to share this information with us.
ReactJS Training in Chennai
AngularJS Training Institute in Chennai
AngularJS Training in Chennai
AWS Training in Chennai
DevOps Certification in Chennai
Robotics Process Automation Training in Chennai
R Programming Training in Chennai
Data Science Course in Chennai

Post a Comment