DelegateFactory.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Reflection.Emit;
  5. namespace Houdar.Core.Util.Common
  6. {
  7. /// <summary>A dynamic delegate factory.
  8. /// </summary>
  9. public class DelegateFactory
  10. {
  11. /// <summary>Creates a delegate from the given methodInfo and parameterTypes.
  12. /// </summary>
  13. /// <typeparam name="D"></typeparam>
  14. /// <param name="methodInfo"></param>
  15. /// <param name="parameterTypes"></param>
  16. /// <returns></returns>
  17. public static D CreateDelegate<D>(MethodInfo methodInfo, Type[] parameterTypes) where D : class
  18. {
  19. if (methodInfo == null)
  20. {
  21. throw new ArgumentNullException("methodInfo");
  22. }
  23. if (parameterTypes == null)
  24. {
  25. throw new ArgumentNullException("parameterTypes");
  26. }
  27. var parameters = methodInfo.GetParameters();
  28. var dynamicMethod = new DynamicMethod(
  29. methodInfo.Name,
  30. MethodAttributes.Static | MethodAttributes.Public,
  31. CallingConventions.Standard,
  32. methodInfo.ReturnType,
  33. parameterTypes,
  34. typeof(object),
  35. true)
  36. {
  37. InitLocals = false
  38. };
  39. var dynamicEmit = new DynamicEmit(dynamicMethod);
  40. if (!methodInfo.IsStatic)
  41. {
  42. dynamicEmit.LoadArgument(0);
  43. dynamicEmit.CastTo(typeof(object), methodInfo.DeclaringType);
  44. }
  45. for (int index = 0; index < parameters.Length; index++)
  46. {
  47. dynamicEmit.LoadArgument(index + 1);
  48. dynamicEmit.CastTo(parameterTypes[index + 1], parameters[index].ParameterType);
  49. }
  50. dynamicEmit.Call(methodInfo);
  51. dynamicEmit.Return();
  52. return dynamicMethod.CreateDelegate(typeof(D)) as D;
  53. }
  54. class DynamicEmit
  55. {
  56. private ILGenerator _ilGenerator;
  57. private static readonly Dictionary<Type, OpCode> _converts = new Dictionary<Type, OpCode>();
  58. static DynamicEmit()
  59. {
  60. _converts.Add(typeof(sbyte), OpCodes.Conv_I1);
  61. _converts.Add(typeof(short), OpCodes.Conv_I2);
  62. _converts.Add(typeof(int), OpCodes.Conv_I4);
  63. _converts.Add(typeof(long), OpCodes.Conv_I8);
  64. _converts.Add(typeof(byte), OpCodes.Conv_U1);
  65. _converts.Add(typeof(ushort), OpCodes.Conv_U2);
  66. _converts.Add(typeof(uint), OpCodes.Conv_U4);
  67. _converts.Add(typeof(ulong), OpCodes.Conv_U8);
  68. _converts.Add(typeof(float), OpCodes.Conv_R4);
  69. _converts.Add(typeof(double), OpCodes.Conv_R8);
  70. _converts.Add(typeof(bool), OpCodes.Conv_I1);
  71. _converts.Add(typeof(char), OpCodes.Conv_U2);
  72. }
  73. public DynamicEmit(DynamicMethod dynamicMethod)
  74. {
  75. this._ilGenerator = dynamicMethod.GetILGenerator();
  76. }
  77. public DynamicEmit(ILGenerator ilGen)
  78. {
  79. this._ilGenerator = ilGen;
  80. }
  81. public void LoadArgument(int argumentIndex)
  82. {
  83. switch (argumentIndex)
  84. {
  85. case 0:
  86. this._ilGenerator.Emit(OpCodes.Ldarg_0);
  87. break;
  88. case 1:
  89. this._ilGenerator.Emit(OpCodes.Ldarg_1);
  90. break;
  91. case 2:
  92. this._ilGenerator.Emit(OpCodes.Ldarg_2);
  93. break;
  94. case 3:
  95. this._ilGenerator.Emit(OpCodes.Ldarg_3);
  96. break;
  97. default:
  98. if (argumentIndex < 0x100)
  99. {
  100. this._ilGenerator.Emit(OpCodes.Ldarg_S, (byte)argumentIndex);
  101. }
  102. else
  103. {
  104. this._ilGenerator.Emit(OpCodes.Ldarg, argumentIndex);
  105. }
  106. break;
  107. }
  108. }
  109. public void CastTo(Type fromType, Type toType)
  110. {
  111. if (fromType != toType)
  112. {
  113. if (toType == typeof(void))
  114. {
  115. if (!(fromType == typeof(void)))
  116. {
  117. this.Pop();
  118. }
  119. }
  120. else
  121. {
  122. if (fromType.IsValueType)
  123. {
  124. if (toType.IsValueType)
  125. {
  126. this.Convert(toType);
  127. return;
  128. }
  129. this._ilGenerator.Emit(OpCodes.Box, fromType);
  130. }
  131. this.CastTo(toType);
  132. }
  133. }
  134. }
  135. public void CastTo(Type toType)
  136. {
  137. if (toType.IsValueType)
  138. {
  139. this._ilGenerator.Emit(OpCodes.Unbox_Any, toType);
  140. }
  141. else
  142. {
  143. this._ilGenerator.Emit(OpCodes.Castclass, toType);
  144. }
  145. }
  146. public void Pop()
  147. {
  148. this._ilGenerator.Emit(OpCodes.Pop);
  149. }
  150. public void Convert(Type toType)
  151. {
  152. this._ilGenerator.Emit(_converts[toType]);
  153. }
  154. public void Return()
  155. {
  156. this._ilGenerator.Emit(OpCodes.Ret);
  157. }
  158. public void Call(MethodInfo method)
  159. {
  160. if (method.IsFinal || !method.IsVirtual)
  161. {
  162. this._ilGenerator.EmitCall(OpCodes.Call, method, null);
  163. }
  164. else
  165. {
  166. this._ilGenerator.EmitCall(OpCodes.Callvirt, method, null);
  167. }
  168. }
  169. }
  170. }
  171. }