DelegateFactory.cs 6.2 KB

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