/src/LinFu.Reflection.Emit/MethodDefinitionExtensions.cs

http://github.com/philiplaureano/LinFu · C# · 187 lines · 87 code · 26 blank · 74 comment · 15 complexity · 65670494888063036dfaeb11468d9aaa MD5 · raw file

  1. using System;
  2. using System.Linq;
  3. using Mono.Cecil;
  4. using Mono.Cecil.Cil;
  5. namespace LinFu.Reflection.Emit
  6. {
  7. /// <summary>
  8. /// A class that extends the <see cref="MethodDefinition" />
  9. /// class with features similar to the features in the
  10. /// System.Reflection.Emit namespace.
  11. /// </summary>
  12. public static class MethodDefinitionExtensions
  13. {
  14. /// <summary>
  15. /// Returns the <see cref="ILProcessor" /> instance
  16. /// associated with the body of the <paramref name="method">target method</paramref>.
  17. /// </summary>
  18. /// <param name="method">The target method to be modified.</param>
  19. /// <returns>The <see cref="ILProcessor" /> instance that points to the instructions of the method body.</returns>
  20. public static ILProcessor GetILGenerator(this MethodDefinition method)
  21. {
  22. return method.Body.GetILProcessor();
  23. }
  24. /// <summary>
  25. /// Adds a <see cref="VariableDefinition">local variable</see>
  26. /// instance to the target <paramref name="methodDef">method definition</paramref>.
  27. /// </summary>
  28. /// <param name="methodDef">The <paramref name="methodDef" /> instance which will contain the local variable.</param>
  29. /// <param name="localType">
  30. /// The object <see cref="System.Type">type</see> that describes the type of objects that will be
  31. /// stored by the local variable.
  32. /// </param>
  33. /// <returns>A <see cref="VariableDefinition" /> that represents the local variable itself.</returns>
  34. public static VariableDefinition AddLocal(this MethodDefinition methodDef, Type localType)
  35. {
  36. var declaringType = methodDef.DeclaringType;
  37. var module = declaringType.Module;
  38. var variableType = module.Import(localType);
  39. var result = new VariableDefinition(variableType);
  40. methodDef.Body.Variables.Add(result);
  41. return result;
  42. }
  43. /// <summary>
  44. /// Adds a named <see cref="VariableDefinition">local variable</see>
  45. /// instance to the target <paramref name="method">method definition</paramref>.
  46. /// </summary>
  47. /// <param name="method">The <paramref name="method" /> instance which will contain the local variable.</param>
  48. /// <param name="variableName">The name of the local variable.</param>
  49. /// <param name="variableType">
  50. /// The object <see cref="System.Type">type</see> that describes the type of objects that will
  51. /// be stored by the local variable.
  52. /// </param>
  53. /// <returns></returns>
  54. public static VariableDefinition AddLocal(this MethodDefinition method, string variableName, Type variableType)
  55. {
  56. var module = method.DeclaringType.Module;
  57. var localType = module.Import(variableType);
  58. VariableDefinition newLocal = null;
  59. foreach (VariableDefinition local in method.Body.Variables)
  60. {
  61. // Match the variable name and type
  62. if (local.Name != variableName || local.VariableType != localType)
  63. continue;
  64. newLocal = local;
  65. }
  66. // If necessary, create the local variable
  67. if (newLocal == null)
  68. {
  69. var body = method.Body;
  70. newLocal = new VariableDefinition(variableName, localType);
  71. body.Variables.Add(newLocal);
  72. }
  73. return newLocal;
  74. }
  75. /// <summary>
  76. /// Adds a set of parameter types to the target <paramref name="method" />.
  77. /// </summary>
  78. /// <param name="method">The target method.</param>
  79. /// <param name="parameterTypes">The list of types that describe the method signature.</param>
  80. public static void AddParameters(this MethodDefinition method, Type[] parameterTypes)
  81. {
  82. var declaringType = method.DeclaringType;
  83. var module = declaringType.Module;
  84. // Build the parameter list
  85. foreach (var type in parameterTypes)
  86. {
  87. TypeReference parameterType;
  88. var isGeneric = type.ContainsGenericParameters && type.IsGenericType;
  89. var hasGenericParameter = type.HasElementType && type.GetElementType().IsGenericParameter;
  90. var shouldImportMethodContext = isGeneric || type.IsGenericParameter || hasGenericParameter;
  91. parameterType = shouldImportMethodContext ? module.Import(type, method) : module.Import(type);
  92. var param = new ParameterDefinition(parameterType);
  93. method.Parameters.Add(param);
  94. }
  95. }
  96. /// <summary>
  97. /// Assigns the <paramref name="returnType" /> for the target method.
  98. /// </summary>
  99. /// <param name="method">The target method.</param>
  100. /// <param name="returnType">The <see cref="System.Type" /> instance that describes the return type.</param>
  101. public static void SetReturnType(this MethodDefinition method, Type returnType)
  102. {
  103. var declaringType = method.DeclaringType;
  104. var module = declaringType.Module;
  105. TypeReference actualReturnType;
  106. if (returnType.ContainsGenericParameters && returnType.IsGenericType || returnType.IsGenericParameter)
  107. actualReturnType = module.Import(returnType, method);
  108. else
  109. actualReturnType = module.Import(returnType);
  110. method.ReturnType = actualReturnType;
  111. }
  112. /// <summary>
  113. /// Adds a generic parameter type to the <paramref name="method" />.
  114. /// </summary>
  115. /// <param name="method">The target method.</param>
  116. /// <param name="parameterType">The parameter type.</param>
  117. /// <returns>A <see cref="TypeReference" /> that represents the generic parameter type.</returns>
  118. public static TypeReference AddGenericParameter(this MethodDefinition method, Type parameterType)
  119. {
  120. // Check if the parameter type already exists
  121. var matches = (from GenericParameter p in method.GenericParameters
  122. where p.Name == parameterType.Name
  123. select p).ToList();
  124. // Reuse the existing parameter
  125. if (matches.Count > 0)
  126. return matches[0];
  127. var parameter = new GenericParameter(parameterType.Name, method);
  128. method.GenericParameters.Add(parameter);
  129. return parameter;
  130. }
  131. /// <summary>
  132. /// Adds a <see cref="VariableDefinition">local variable</see>
  133. /// instance to the target <paramref name="methodDef">method definition</paramref>.
  134. /// </summary>
  135. /// <typeparam name="T">
  136. /// The object <see cref="System.Type">type</see> that describes the type of objects that will be
  137. /// stored by the local variable.
  138. /// </typeparam>
  139. /// <param name="methodDef">The <paramref name="methodDef" /> instance which will contain the local variable.</param>
  140. /// <returns>A <see cref="VariableDefinition" /> that represents the local variable itself.</returns>
  141. public static VariableDefinition AddLocal<T>(this MethodDefinition methodDef)
  142. {
  143. return methodDef.AddLocal(typeof(T));
  144. }
  145. /// <summary>
  146. /// Adds a named <see cref="VariableDefinition">local variable</see>
  147. /// instance to the target <paramref name="methodDef">method definition</paramref>.
  148. /// </summary>
  149. /// <typeparam name="T">
  150. /// The object <see cref="System.Type">type</see> that describes the type of objects that will be
  151. /// stored by the local variable.
  152. /// </typeparam>
  153. /// <param name="methodDef">The <paramref name="methodDef" /> instance which will contain the local variable.</param>
  154. /// <param name="variableName">The name of the local variable.</param>
  155. /// <returns>A <see cref="VariableDefinition" /> that represents the local variable itself.</returns>
  156. public static VariableDefinition AddLocal<T>(this MethodDefinition methodDef, string variableName)
  157. {
  158. return methodDef.AddLocal(variableName, typeof(T));
  159. }
  160. }
  161. }