Wednesday, 7 July 2010

CONVERTING METHODINFO INTO A DELEGATE INSTANCE TO IMPROVE PERFORMANCE

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

No comments:

Post a Comment