/src/Manos/Manos.Routing/ParameterizedActionFactory.cs

http://github.com/jacksonh/manos · C# · 142 lines · 97 code · 18 blank · 27 comment · 11 complexity · 053fa4d2ef05fc197d703967f246b60e MD5 · raw file

  1. //
  2. // Copyright (C) 2010 Jackson Harper (jackson@manosdemono.com)
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining
  5. // a copy of this software and associated documentation files (the
  6. // "Software"), to deal in the Software without restriction, including
  7. // without limitation the rights to use, copy, modify, merge, publish,
  8. // distribute, sublicense, and/or sell copies of the Software, and to
  9. // permit persons to whom the Software is furnished to do so, subject to
  10. // the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be
  13. // included in all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. //
  23. //
  24. using System;
  25. using System.Reflection;
  26. using System.Reflection.Emit;
  27. //
  28. // Adapted from example code here:
  29. // http://www.codeproject.com/KB/cs/FastInvokerWrapper.aspx
  30. //
  31. namespace Manos.Routing
  32. {
  33. public static class ParameterizedActionFactory
  34. {
  35. public static ParameterizedAction CreateAction (MethodInfo method)
  36. {
  37. DynamicMethod dynamic = new DynamicMethod (String.Empty, typeof (void),
  38. new Type [] { typeof(object), typeof(object[]) },
  39. method.DeclaringType.Module);
  40. ILGenerator codegen = dynamic.GetILGenerator ();
  41. ParameterInfo [] parameters = method.GetParameters ();
  42. Type [] param_types = new Type [parameters.Length];
  43. for (int i = 0; i < param_types.Length; i++)
  44. {
  45. if (parameters [i].ParameterType.IsByRef) {
  46. Console.Error.WriteLine ("By Ref parameters are not allowed in Action signatures.");
  47. return null;
  48. }
  49. param_types [i] = parameters [i].ParameterType;
  50. }
  51. LocalBuilder [] locals = new LocalBuilder [param_types.Length];
  52. for (int i = 0; i < param_types.Length; i++) {
  53. locals [i] = codegen.DeclareLocal (param_types [i], true);
  54. }
  55. for (int i = 0; i < param_types.Length; i++) {
  56. codegen.Emit (OpCodes.Ldarg_1);
  57. EmitFastInt (codegen, i);
  58. codegen.Emit (OpCodes.Ldelem_Ref);
  59. EmitCastToReference (codegen, param_types [i]);
  60. codegen.Emit (OpCodes.Stloc, locals [i]);
  61. }
  62. if (!method.IsStatic) {
  63. codegen.Emit (OpCodes.Ldarg_0);
  64. }
  65. for (int i = 0; i < param_types.Length; i++) {
  66. codegen.Emit (OpCodes.Ldloc, locals [i]);
  67. }
  68. if (method.IsStatic)
  69. codegen.EmitCall (OpCodes.Call, method, null);
  70. else
  71. codegen.EmitCall(OpCodes.Callvirt, method, null);
  72. codegen.Emit (OpCodes.Ret);
  73. ParameterizedAction action = (ParameterizedAction) dynamic.CreateDelegate (typeof(ParameterizedAction));
  74. return action;
  75. }
  76. private static void EmitCastToReference (ILGenerator il, Type type)
  77. {
  78. if (type.IsValueType)
  79. il.Emit (OpCodes.Unbox_Any, type);
  80. else
  81. il.Emit (OpCodes.Castclass, type);
  82. }
  83. private static void EmitFastInt(ILGenerator il, int value)
  84. {
  85. switch (value)
  86. {
  87. case -1:
  88. il.Emit (OpCodes.Ldc_I4_M1);
  89. return;
  90. case 0:
  91. il.Emit (OpCodes.Ldc_I4_0);
  92. return;
  93. case 1:
  94. il.Emit (OpCodes.Ldc_I4_1);
  95. return;
  96. case 2:
  97. il.Emit (OpCodes.Ldc_I4_2);
  98. return;
  99. case 3:
  100. il.Emit (OpCodes.Ldc_I4_3);
  101. return;
  102. case 4:
  103. il.Emit (OpCodes.Ldc_I4_4);
  104. return;
  105. case 5:
  106. il.Emit (OpCodes.Ldc_I4_5);
  107. return;
  108. case 6:
  109. il.Emit (OpCodes.Ldc_I4_6);
  110. return;
  111. case 7:
  112. il.Emit (OpCodes.Ldc_I4_7);
  113. return;
  114. case 8:
  115. il.Emit (OpCodes.Ldc_I4_8);
  116. return;
  117. }
  118. if (value > -129 && value < 128)
  119. il.Emit (OpCodes.Ldc_I4_S, (SByte) value);
  120. else
  121. il.Emit (OpCodes.Ldc_I4, value);
  122. }
  123. }
  124. }