Converting MethodInfo into a delegate instance to improve performance


/ Published in: C#
Save to your folder(s)



Copy this code and paste it in your HTML
  1. using System;
  2. using System.Reflection;
  3. using System.Text;
  4.  
  5. public class Test
  6. {
  7. static void Main()
  8. {
  9. MethodInfo indexOf = typeof(string).GetMethod("IndexOf", new Type[]{typeof(char)});
  10. MethodInfo getByteCount = typeof(Encoding).GetMethod("GetByteCount", new Type[]{typeof(string)});
  11.  
  12. Func<string, object, object> indexOfFunc = MagicMethod<string>(indexOf);
  13. Func<Encoding, object, object> getByteCountFunc = MagicMethod<Encoding>(getByteCount);
  14.  
  15. Console.WriteLine(indexOfFunc("Hello", 'e'));
  16. Console.WriteLine(getByteCountFunc(Encoding.UTF8, "Euro sign: \u20ac"));
  17. }
  18.  
  19. static Func<T, object, object> MagicMethod<T>(MethodInfo method) where T : class
  20. {
  21. // First fetch the generic form
  22. MethodInfo genericHelper = typeof(Test).GetMethod("MagicMethodHelper",
  23. BindingFlags.Static | BindingFlags.NonPublic);
  24.  
  25. // Now supply the type arguments
  26. MethodInfo constructedHelper = genericHelper.MakeGenericMethod
  27. (typeof(T), method.GetParameters()[0].ParameterType, method.ReturnType);
  28.  
  29. // Now call it. The null argument is because it's a static method.
  30. object ret = constructedHelper.Invoke(null, new object[] {method});
  31.  
  32. // Cast the result to the right kind of delegate and return it
  33. return (Func<T, object, object>) ret;
  34. }
  35.  
  36. static Func<TTarget, object, object> MagicMethodHelper<TTarget, TParam, TReturn>(MethodInfo method)
  37. where TTarget : class
  38. {
  39. // Convert the slow MethodInfo into a fast, strongly typed, open delegate
  40. Func<TTarget, TParam, TReturn> func = (Func<TTarget, TParam, TReturn>)Delegate.CreateDelegate
  41. (typeof(Func<TTarget, TParam, TReturn>), method);
  42.  
  43. // Now create a more weakly typed delegate which will call the strongly typed one
  44. Func<TTarget, object, object> ret = (TTarget target, object param) => func(target, (TParam) param);
  45. return ret;
  46. }
  47. }
  48.  
  49.  
  50. // Or, for C# 3+
  51. public static void Main(string[] args)
  52. {
  53. var indexOf = typeof(string).GetMethod("IndexOf", new[] { typeof(char) });
  54. var getByteCount = typeof(Encoding).GetMethod("GetByteCount", new[] { typeof(string) });
  55. var indexOfFunc = MagicMethod<string>(indexOf);
  56. var getByteCountFunc = MagicMethod<Encoding>(getByteCount);
  57. Console.WriteLine(indexOfFunc("Hello", 'e'));
  58. Console.WriteLine(getByteCountFunc(Encoding.UTF8, "Euro sign: \u20ac"));
  59. }
  60.  
  61. static Func<T, object, object> MagicMethod<T>(MethodInfo method)
  62. {
  63. var parameter = method.GetParameters().Single();
  64. var instance = Expression.Parameter(typeof (T), "instance");
  65. var argument = Expression.Parameter(typeof (object), "argument");
  66. var methodCall = Expression.Call(
  67. instance,
  68. method,
  69. Expression.Convert(argument, parameter.ParameterType)
  70. );
  71. return Expression.Lambda<Func<T, object, object>>(
  72. Expression.Convert(methodCall, typeof (object)),
  73. instance, argument
  74. ).Compile();
  75. }

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

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.