Return to Snippet

Revision: 24847
at March 12, 2010 10:16 by pckujawa


Updated Code
using System;
using System.Reflection;
using System.Text;

public class Test
{
    static void Main()
    {
        MethodInfo indexOf = typeof(string).GetMethod("IndexOf", new Type[]{typeof(char)});
        MethodInfo getByteCount = typeof(Encoding).GetMethod("GetByteCount", new Type[]{typeof(string)});
       
        Func<string, object, object> indexOfFunc = MagicMethod<string>(indexOf);
        Func<Encoding, object, object> getByteCountFunc = MagicMethod<Encoding>(getByteCount);
       
        Console.WriteLine(indexOfFunc("Hello", 'e'));
        Console.WriteLine(getByteCountFunc(Encoding.UTF8, "Euro sign: \u20ac"));
    }
   
    static Func<T, object, object> MagicMethod<T>(MethodInfo method) where T : class
    {
        // First fetch the generic form
        MethodInfo genericHelper = typeof(Test).GetMethod("MagicMethodHelper",
            BindingFlags.Static | BindingFlags.NonPublic);
       
        // Now supply the type arguments
        MethodInfo constructedHelper = genericHelper.MakeGenericMethod
            (typeof(T), method.GetParameters()[0].ParameterType, method.ReturnType);
           
        // Now call it. The null argument is because it's a static method.
        object ret = constructedHelper.Invoke(null, new object[] {method});
       
        // Cast the result to the right kind of delegate and return it
        return (Func<T, object, object>) ret;
    }   
       
    static Func<TTarget, object, object> MagicMethodHelper<TTarget, TParam, TReturn>(MethodInfo method)
        where TTarget : class
    {
        // Convert the slow MethodInfo into a fast, strongly typed, open delegate
        Func<TTarget, TParam, TReturn> func = (Func<TTarget, TParam, TReturn>)Delegate.CreateDelegate
            (typeof(Func<TTarget, TParam, TReturn>), method);
       
        // Now create a more weakly typed delegate which will call the strongly typed one
        Func<TTarget, object, object> ret = (TTarget target, object param) => func(target, (TParam) param);
        return ret;
    }
}


// Or, for C# 3+
public static void Main(string[] args)
{
   var indexOf = typeof(string).GetMethod("IndexOf", new[] { typeof(char) });
   var getByteCount = typeof(Encoding).GetMethod("GetByteCount", new[] { typeof(string) });
   var indexOfFunc = MagicMethod<string>(indexOf);
   var getByteCountFunc = MagicMethod<Encoding>(getByteCount);
   Console.WriteLine(indexOfFunc("Hello", 'e'));
   Console.WriteLine(getByteCountFunc(Encoding.UTF8, "Euro sign: \u20ac"));
}

static Func<T, object, object> MagicMethod<T>(MethodInfo method)
{
   var parameter = method.GetParameters().Single();
   var instance = Expression.Parameter(typeof (T), "instance");
   var argument = Expression.Parameter(typeof (object), "argument");
   var methodCall = Expression.Call(
       instance,
       method,
       Expression.Convert(argument, parameter.ParameterType)
       );
   return Expression.Lambda<Func<T, object, object>>(
       Expression.Convert(methodCall, typeof (object)),
       instance, argument
       ).Compile();
}

Revision: 24846
at March 12, 2010 10:14 by pckujawa


Updated Code
using System;
using System.Reflection;
using System.Text;

public class Test
{
    static void Main()
    {
        MethodInfo indexOf = typeof(string).GetMethod("IndexOf", new Type[]{typeof(char)});
        MethodInfo getByteCount = typeof(Encoding).GetMethod("GetByteCount", new Type[]{typeof(string)});
       
        Func<string, object, object> indexOfFunc = MagicMethod<string>(indexOf);
        Func<Encoding, object, object> getByteCountFunc = MagicMethod<Encoding>(getByteCount);
       
        Console.WriteLine(indexOfFunc("Hello", 'e'));
        Console.WriteLine(getByteCountFunc(Encoding.UTF8, "Euro sign: \u20ac"));
    }
   
    static Func<T, object, object> MagicMethod<T>(MethodInfo method) where T : class
    {
        // First fetch the generic form
        MethodInfo genericHelper = typeof(Test).GetMethod("MagicMethodHelper",
            BindingFlags.Static | BindingFlags.NonPublic);
       
        // Now supply the type arguments
        MethodInfo constructedHelper = genericHelper.MakeGenericMethod
            (typeof(T), method.GetParameters()[0].ParameterType, method.ReturnType);
           
        // Now call it. The null argument is because it's a static method.
        object ret = constructedHelper.Invoke(null, new object[] {method});
       
        // Cast the result to the right kind of delegate and return it
        return (Func<T, object, object>) ret;
    }   
       
    static Func<TTarget, object, object> MagicMethodHelper<TTarget, TParam, TReturn>(MethodInfo method)
        where TTarget : class
    {
        // Convert the slow MethodInfo into a fast, strongly typed, open delegate
        Func<TTarget, TParam, TReturn> func = (Func<TTarget, TParam, TReturn>)Delegate.CreateDelegate
            (typeof(Func<TTarget, TParam, TReturn>), method);
       
        // Now create a more weakly typed delegate which will call the strongly typed one
        Func<TTarget, object, object> ret = (TTarget target, object param) => func(target, (TParam) param);
        return ret;
    }
}

Revision: 24845
at March 12, 2010 10:13 by pckujawa


Initial Code
using System;
using System.Reflection;
using System.Text;

public class Test
{
    static void Main()
    {
        MethodInfo indexOf = typeof(string).GetMethod(\"IndexOf\", new Type[]{typeof(char)});
        MethodInfo getByteCount = typeof(Encoding).GetMethod(\"GetByteCount\", new Type[]{typeof(string)});
       
        Func<string, object, object> indexOfFunc = MagicMethod<string>(indexOf);
        Func<Encoding, object, object> getByteCountFunc = MagicMethod<Encoding>(getByteCount);
       
        Console.WriteLine(indexOfFunc(\"Hello\", \'e\'));
        Console.WriteLine(getByteCountFunc(Encoding.UTF8, \"Euro sign: \\u20ac\"));
    }
   
    static Func<T, object, object> MagicMethod<T>(MethodInfo method) where T : class
    {
        // First fetch the generic form
        MethodInfo genericHelper = typeof(Test).GetMethod(\"MagicMethodHelper\",
            BindingFlags.Static | BindingFlags.NonPublic);
       
        // Now supply the type arguments
        MethodInfo constructedHelper = genericHelper.MakeGenericMethod
            (typeof(T), method.GetParameters()[0].ParameterType, method.ReturnType);
           
        // Now call it. The null argument is because it\'s a static method.
        object ret = constructedHelper.Invoke(null, new object[] {method});
       
        // Cast the result to the right kind of delegate and return it
        return (Func<T, object, object>) ret;
    }   
       
    static Func<TTarget, object, object> MagicMethodHelper<TTarget, TParam, TReturn>(MethodInfo method)
        where TTarget : class
    {
        // Convert the slow MethodInfo into a fast, strongly typed, open delegate
        Func<TTarget, TParam, TReturn> func = (Func<TTarget, TParam, TReturn>)Delegate.CreateDelegate
            (typeof(Func<TTarget, TParam, TReturn>), method);
       
        // Now create a more weakly typed delegate which will call the strongly typed one
        Func<TTarget, object, object> ret = (TTarget target, object param) => func(target, (TParam) param);
        return ret;
    }
}

Initial URL
http://msmvps.com/blogs/jon_skeet/archive/2008/08/09/making-reflection-fly-and-exploring-delegates.aspx

Initial Description


Initial Title
Converting MethodInfo into a delegate instance to improve performance

Initial Tags


Initial Language
C#