PageRenderTime 37ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Web.Mvc2/System.Web.Mvc/DynamicTypeGenerator.cs

https://github.com/iainlane/mono
C# | 125 lines | 77 code | 19 blank | 29 comment | 5 complexity | 9f5f9b5c3915518c37c3d5ff6bf2cbc8 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation. All rights reserved.
  4. *
  5. * This software is subject to the Microsoft Public License (Ms-PL).
  6. * A copy of the license can be found in the license.htm file included
  7. * in this distribution.
  8. *
  9. * You must not remove this notice, or any other, from this software.
  10. *
  11. * ***************************************************************************/
  12. namespace System.Web.Mvc {
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Reflection;
  17. using System.Reflection.Emit;
  18. using System.Security;
  19. internal static class DynamicTypeGenerator {
  20. private static readonly ModuleBuilder _dynamicModule = CreateDynamicModule();
  21. private static ModuleBuilder CreateDynamicModule() {
  22. // DDB 226615 - since MVC is [SecurityTransparent], the dynamic assembly must declare itself likewise
  23. CustomAttributeBuilder builder = new CustomAttributeBuilder(
  24. typeof(SecurityTransparentAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
  25. CustomAttributeBuilder[] assemblyAttributes = new CustomAttributeBuilder[] { builder };
  26. AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
  27. new AssemblyName("System.Web.Mvc.{Dynamic}"), AssemblyBuilderAccess.Run, assemblyAttributes);
  28. ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("System.Web.Mvc.{Dynamic}.dll");
  29. return dynamicModule;
  30. }
  31. // Creates a new dynamic type that is a subclassed type of baseType and also implements methods of the specified
  32. // interfaces. The base type must already have method signatures that implicitly implement the given
  33. // interfaces. The signatures of all public (e.g. not private / internal) constructors from the baseType
  34. // will be duplicated for the subclassed type and the new constructors made public.
  35. public static Type GenerateType(string dynamicTypeName, Type baseType, IEnumerable<Type> interfaceTypes) {
  36. TypeBuilder newType = _dynamicModule.DefineType(
  37. "System.Web.Mvc.{Dynamic}." + dynamicTypeName,
  38. TypeAttributes.AutoLayout | TypeAttributes.Public | TypeAttributes.Class,
  39. baseType);
  40. foreach (Type interfaceType in interfaceTypes) {
  41. newType.AddInterfaceImplementation(interfaceType);
  42. foreach (MethodInfo interfaceMethod in interfaceType.GetMethods()) {
  43. ImplementInterfaceMethod(newType, interfaceMethod);
  44. }
  45. }
  46. // generate new constructors for each accessible base constructor
  47. foreach (ConstructorInfo ctor in baseType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
  48. switch (ctor.Attributes & MethodAttributes.MemberAccessMask) {
  49. case MethodAttributes.Family:
  50. case MethodAttributes.Public:
  51. case MethodAttributes.FamORAssem:
  52. ImplementConstructor(newType, ctor);
  53. break;
  54. }
  55. }
  56. Type bakedType = newType.CreateType();
  57. return bakedType;
  58. }
  59. // generates this constructor:
  60. // public NewType(param0, param1, ...) : base(param0, param1, ...) { }
  61. private static void ImplementConstructor(TypeBuilder newType, ConstructorInfo baseCtor) {
  62. ParameterInfo[] parameters = baseCtor.GetParameters();
  63. Type[] parameterTypes = (from p in parameters select p.ParameterType).ToArray();
  64. ConstructorBuilder newCtor = newType.DefineConstructor(
  65. (baseCtor.Attributes & ~MethodAttributes.MemberAccessMask) | MethodAttributes.Public /* force public constructor */,
  66. baseCtor.CallingConvention, parameterTypes);
  67. // parameter 0 is 'this', so we start at index 1
  68. for (int i = 0; i < parameters.Length; i++) {
  69. newCtor.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name);
  70. }
  71. // load all arguments (including 'this') in proper order, then call and return
  72. ILGenerator ilGen = newCtor.GetILGenerator();
  73. for (int i = 0; i <= parameterTypes.Length; i++) {
  74. ilGen.Emit(OpCodes.Ldarg_S, (byte)i);
  75. }
  76. ilGen.Emit(OpCodes.Call, baseCtor);
  77. ilGen.Emit(OpCodes.Ret);
  78. }
  79. // generates this explicit interface method:
  80. // public new Interface.Method(param0, param1, ...) {
  81. // return base.Method(param0, param1, ...);
  82. // }
  83. private static void ImplementInterfaceMethod(TypeBuilder newType, MethodInfo interfaceMethod) {
  84. ParameterInfo[] parameters = interfaceMethod.GetParameters();
  85. Type[] parameterTypes = (from p in parameters select p.ParameterType).ToArray();
  86. // based on http://msdn.microsoft.com/en-us/library/system.reflection.emit.typebuilder.definemethodoverride.aspx
  87. MethodBuilder newMethod = newType.DefineMethod(interfaceMethod.DeclaringType.Name + "." + interfaceMethod.Name,
  88. MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
  89. interfaceMethod.ReturnType, parameterTypes);
  90. MethodInfo baseMethod = newType.BaseType.GetMethod(interfaceMethod.Name, parameterTypes);
  91. // parameter 0 is 'this', so we start at index 1
  92. for (int i = 0; i < parameters.Length; i++) {
  93. newMethod.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name);
  94. }
  95. // load all arguments (including 'this') in proper order, then call and return
  96. ILGenerator ilGen = newMethod.GetILGenerator();
  97. for (int i = 0; i <= parameterTypes.Length; i++) {
  98. ilGen.Emit(OpCodes.Ldarg_S, (byte)i);
  99. }
  100. ilGen.Emit(OpCodes.Call, baseMethod);
  101. ilGen.Emit(OpCodes.Ret);
  102. // finally, hook the new method up to the interface mapping
  103. newType.DefineMethodOverride(newMethod, interfaceMethod);
  104. }
  105. }
  106. }