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