private static void CopyGenericParameterInformation( GenericTypeParameterBuilder parameterTo, Type parameterFrom) { if (parameterTo == null) { throw new ArgumentNullException(nameof(parameterTo)); } if (parameterFrom == null) { throw new ArgumentNullException(nameof(parameterFrom)); } if (!parameterFrom.IsGenericParameter) { throw new ArgumentException($"{parameterFrom.FullName} isn't a generic parameter."); } // We need to eliminate co-contra variant attributes // because they can be specified only on interfaces. const GenericParameterAttributes AttributesMask = ~(GenericParameterAttributes.Contravariant | GenericParameterAttributes.Covariant); // Copy attributes: class, struct, new() etc. parameterTo.SetGenericParameterAttributes(parameterFrom.GenericParameterAttributes & AttributesMask); var constraints = parameterFrom.GetGenericParameterConstraints(); var baseTypeConstraint = constraints.SingleOrDefault(t => t.IsClass); var interfaceConstraint = constraints.Where(t => t.IsInterface).ToArray(); if (baseTypeConstraint != null) { parameterTo.SetBaseTypeConstraint(baseTypeConstraint); } if (interfaceConstraint.Length != 0) { parameterTo.SetInterfaceConstraints(interfaceConstraint); } }
/// <summary><![CDATA[ /// [Serializable] public sealed class DynamicEnumComparer<TEnum> : EnumComparer<TEnum> where TEnum : struct, Enum /// ]]></summary> private static Type BuildGenericComparer(Type underlyingType) { TypeBuilder builder = ModuleBuilder.DefineType($"DynamicEnumComparer{underlyingType.Name}`1", TypeAttributes.Public | TypeAttributes.Sealed, typeof(EnumComparer <>)); builder.SetCustomAttribute(new CustomAttributeBuilder(typeof(SerializableAttribute).GetDefaultConstructor(), Reflector.EmptyObjects)); GenericTypeParameterBuilder tEnum = builder.DefineGenericParameters("TEnum")[0]; tEnum.SetGenericParameterAttributes(GenericParameterAttributes.NotNullableValueTypeConstraint); tEnum.SetBaseTypeConstraint(Reflector.EnumType); GenerateDynamicEnumComparerCtor(builder); GenerateEquals(builder, tEnum); GenerateGetHashCode(builder, underlyingType, tEnum); GenerateCompare(builder, underlyingType, tEnum); GenerateToEnum(builder, underlyingType, tEnum); GenerateToUInt64(builder, underlyingType, tEnum); GenerateToInt64(builder, underlyingType, tEnum); return(builder.CreateType()); }
public static void Main() { // The following shows the usage syntax of the C# // version of the generic method emitted by this program. // Note that the generic parameters must be specified // explicitly, because the compiler does not have enough // context to infer the type of TOutput. In this case, TOutput // is a generic List containing strings. // string[] arr = { "a", "b", "c", "d", "e" }; List <string> list1 = GenericMethodBuilder.Factory <string, List <string> >(arr); Console.WriteLine("The first element is: {0}", list1[0]); // Creating a dynamic assembly requires an AssemblyName // object, and the current application domain. // AssemblyName asmName = new AssemblyName("DemoMethodBuilder1"); AssemblyBuilder demoAssembly = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run); // Define the module that contains the code. For an // assembly with one module, the module name is the // assembly name plus a file extension. ModuleBuilder demoModule = demoAssembly.DefineDynamicModule(asmName.Name); // Define a type to contain the method. TypeBuilder demoType = demoModule.DefineType("DemoType", TypeAttributes.Public); // Define a public static method with standard calling // conventions. Do not specify the parameter types or the // return type, because type parameters will be used for // those types, and the type parameters have not been // defined yet. // MethodBuilder factory = demoType.DefineMethod("Factory", MethodAttributes.Public | MethodAttributes.Static); // Defining generic type parameters for the method makes it a // generic method. To make the code easier to read, each // type parameter is copied to a variable of the same name. // string[] typeParameterNames = { "TInput", "TOutput" }; GenericTypeParameterBuilder[] typeParameters = factory.DefineGenericParameters(typeParameterNames); GenericTypeParameterBuilder TInput = typeParameters[0]; GenericTypeParameterBuilder TOutput = typeParameters[1]; // Add special constraints. // The type parameter TOutput is constrained to be a reference // type, and to have a parameterless constructor. This ensures // that the Factory method can create the collection type. // TOutput.SetGenericParameterAttributes( GenericParameterAttributes.ReferenceTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint); // Add interface and base type constraints. // The type parameter TOutput is constrained to types that // implement the ICollection<T> interface, to ensure that // they have an Add method that can be used to add elements. // // To create the constraint, first use MakeGenericType to bind // the type parameter TInput to the ICollection<T> interface, // returning the type ICollection<TInput>, then pass // the newly created type to the SetInterfaceConstraints // method. The constraints must be passed as an array, even if // there is only one interface. // Type icoll = typeof(ICollection <>); Type icollOfTInput = icoll.MakeGenericType(TInput); Type[] constraints = { icollOfTInput }; TOutput.SetInterfaceConstraints(constraints); // Set parameter types for the method. The method takes // one parameter, an array of type TInput. Type[] parms = { TInput.MakeArrayType() }; factory.SetParameters(parms); // Set the return type for the method. The return type is // the generic type parameter TOutput. factory.SetReturnType(TOutput); // Generate a code body for the method. // ----------------------------------- // Get a code generator and declare local variables and // labels. Save the input array to a local variable. // ILGenerator ilgen = factory.GetILGenerator(); LocalBuilder retVal = ilgen.DeclareLocal(TOutput); LocalBuilder ic = ilgen.DeclareLocal(icollOfTInput); LocalBuilder input = ilgen.DeclareLocal(TInput.MakeArrayType()); LocalBuilder index = ilgen.DeclareLocal(typeof(int)); Label enterLoop = ilgen.DefineLabel(); Label loopAgain = ilgen.DefineLabel(); ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Stloc_S, input); // Create an instance of TOutput, using the generic method // overload of the Activator.CreateInstance method. // Using this overload requires the specified type to have // a parameterless constructor, which is the reason for adding // that constraint to TOutput. Create the constructed generic // method by passing TOutput to MakeGenericMethod. After // emitting code to call the method, emit code to store the // new TOutput in a local variable. // MethodInfo createInst = typeof(Activator).GetMethod("CreateInstance", Type.EmptyTypes); MethodInfo createInstOfTOutput = createInst.MakeGenericMethod(TOutput); ilgen.Emit(OpCodes.Call, createInstOfTOutput); ilgen.Emit(OpCodes.Stloc_S, retVal); // Load the reference to the TOutput object, cast it to // ICollection<TInput>, and save it. // ilgen.Emit(OpCodes.Ldloc_S, retVal); ilgen.Emit(OpCodes.Box, TOutput); ilgen.Emit(OpCodes.Castclass, icollOfTInput); ilgen.Emit(OpCodes.Stloc_S, ic); // Loop through the array, adding each element to the new // instance of TOutput. Note that in order to get a MethodInfo // for ICollection<TInput>.Add, it is necessary to first // get the Add method for the generic type defintion, // ICollection<T>.Add. This is because it is not possible // to call GetMethod on icollOfTInput. The static overload of // TypeBuilder.GetMethod produces the correct MethodInfo for // the constructed type. // MethodInfo mAddPrep = icoll.GetMethod("Add"); MethodInfo mAdd = TypeBuilder.GetMethod(icollOfTInput, mAddPrep); // Initialize the count and enter the loop. ilgen.Emit(OpCodes.Ldc_I4_0); ilgen.Emit(OpCodes.Stloc_S, index); ilgen.Emit(OpCodes.Br_S, enterLoop); // Mark the beginning of the loop. Push the ICollection // reference on the stack, so it will be in position for the // call to Add. Then push the array and the index on the // stack, get the array element, and call Add (represented // by the MethodInfo mAdd) to add it to the collection. // // The other ten instructions just increment the index // and test for the end of the loop. Note the MarkLabel // method, which sets the point in the code where the // loop is entered. (See the earlier Br_S to enterLoop.) // ilgen.MarkLabel(loopAgain); ilgen.Emit(OpCodes.Ldloc_S, ic); ilgen.Emit(OpCodes.Ldloc_S, input); ilgen.Emit(OpCodes.Ldloc_S, index); ilgen.Emit(OpCodes.Ldelem, TInput); ilgen.Emit(OpCodes.Callvirt, mAdd); ilgen.Emit(OpCodes.Ldloc_S, index); ilgen.Emit(OpCodes.Ldc_I4_1); ilgen.Emit(OpCodes.Add); ilgen.Emit(OpCodes.Stloc_S, index); ilgen.MarkLabel(enterLoop); ilgen.Emit(OpCodes.Ldloc_S, index); ilgen.Emit(OpCodes.Ldloc_S, input); ilgen.Emit(OpCodes.Ldlen); ilgen.Emit(OpCodes.Conv_I4); ilgen.Emit(OpCodes.Clt); ilgen.Emit(OpCodes.Brtrue_S, loopAgain); ilgen.Emit(OpCodes.Ldloc_S, retVal); ilgen.Emit(OpCodes.Ret); // Complete the type. Type dt = demoType.CreateType(); // To create a constructed generic method that can be // executed, first call the GetMethod method on the completed // type to get the generic method definition. Call MakeGenericType // on the generic method definition to obtain the constructed // method, passing in the type arguments. In this case, the // constructed method has string for TInput and List<string> // for TOutput. // MethodInfo m = dt.GetMethod("Factory"); MethodInfo bound = m.MakeGenericMethod(typeof(string), typeof(List <string>)); // Display a string representing the bound method. Console.WriteLine(bound); // Once the generic method is constructed, // you can invoke it and pass in an array of objects // representing the arguments. In this case, there is only // one element in that array, the argument 'arr'. // object o = bound.Invoke(null, new object[] { arr }); List <string> list2 = (List <string>)o; Console.WriteLine("The first element is: {0}", list2[0]); // You can get better performance from multiple calls if // you bind the constructed method to a delegate. The // following code uses the generic delegate D defined // earlier. // Type dType = typeof(D <string, List <string> >); D <string, List <string> > test; test = (D <string, List <string> >)Delegate.CreateDelegate(dType, bound); List <string> list3 = test(arr); Console.WriteLine("The first element is: {0}", list3[0]); }
public static void Main() { // Define a dynamic assembly to contain the sample type. The // assembly will not be run, but only saved to disk, so // AssemblyBuilderAccess.Save is specified. // //<Snippet2> AppDomain myDomain = AppDomain.CurrentDomain; AssemblyName myAsmName = new AssemblyName("GenericEmitExample1"); AssemblyBuilder myAssembly = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave); //</Snippet2> // An assembly is made up of executable modules. For a single- // module assembly, the module name and file name are the same // as the assembly name. // //<Snippet3> ModuleBuilder myModule = myAssembly.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll"); //</Snippet3> // Get type objects for the base class trivial interfaces to // be used as constraints. // Type baseType = typeof(ExampleBase); Type interfaceA = typeof(IExampleA); Type interfaceB = typeof(IExampleB); // Define the sample type. // //<Snippet4> TypeBuilder myType = myModule.DefineType("Sample", TypeAttributes.Public); //</Snippet4> Console.WriteLine("Type 'Sample' is generic: {0}", myType.IsGenericType); // Define type parameters for the type. Until you do this, // the type is not generic, as the preceding and following // WriteLine statements show. The type parameter names are // specified as an array of strings. To make the code // easier to read, each GenericTypeParameterBuilder is placed // in a variable with the same name as the type parameter. // //<Snippet5> string[] typeParamNames = { "TFirst", "TSecond" }; GenericTypeParameterBuilder[] typeParams = myType.DefineGenericParameters(typeParamNames); GenericTypeParameterBuilder TFirst = typeParams[0]; GenericTypeParameterBuilder TSecond = typeParams[1]; //</Snippet5> Console.WriteLine("Type 'Sample' is generic: {0}", myType.IsGenericType); // Apply constraints to the type parameters. // // A type that is substituted for the first parameter, TFirst, // must be a reference type and must have a parameterless // constructor. //<Snippet6> TFirst.SetGenericParameterAttributes( GenericParameterAttributes.DefaultConstructorConstraint | GenericParameterAttributes.ReferenceTypeConstraint); //</Snippet6> // A type that is substituted for the second type // parameter must implement IExampleA and IExampleB, and // inherit from the trivial test class ExampleBase. The // interface constraints are specified as an array // containing the interface types. //<Snippet7> TSecond.SetBaseTypeConstraint(baseType); Type[] interfaceTypes = { interfaceA, interfaceB }; TSecond.SetInterfaceConstraints(interfaceTypes); //</Snippet7> // The following code adds a private field named ExampleField, // of type TFirst. //<Snippet21> FieldBuilder exField = myType.DefineField("ExampleField", TFirst, FieldAttributes.Private); //</Snippet21> // Define a static method that takes an array of TFirst and // returns a List<TFirst> containing all the elements of // the array. To define this method it is necessary to create // the type List<TFirst> by calling MakeGenericType on the // generic type definition, List<T>. (The T is omitted with // the typeof operator when you get the generic type // definition.) The parameter type is created by using the // MakeArrayType method. // //<Snippet22> Type listOf = typeof(List <>); Type listOfTFirst = listOf.MakeGenericType(TFirst); Type[] mParamTypes = { TFirst.MakeArrayType() }; MethodBuilder exMethod = myType.DefineMethod("ExampleMethod", MethodAttributes.Public | MethodAttributes.Static, listOfTFirst, mParamTypes); //</Snippet22> // Emit the method body. // The method body consists of just three opcodes, to load // the input array onto the execution stack, to call the // List<TFirst> constructor that takes IEnumerable<TFirst>, // which does all the work of putting the input elements into // the list, and to return, leaving the list on the stack. The // hard work is getting the constructor. // // The GetConstructor method is not supported on a // GenericTypeParameterBuilder, so it is not possible to get // the constructor of List<TFirst> directly. There are two // steps, first getting the constructor of List<T> and then // calling a method that converts it to the corresponding // constructor of List<TFirst>. // // The constructor needed here is the one that takes an // IEnumerable<T>. Note, however, that this is not the // generic type definition of IEnumerable<T>; instead, the // T from List<T> must be substituted for the T of // IEnumerable<T>. (This seems confusing only because both // types have type parameters named T. That is why this example // uses the somewhat silly names TFirst and TSecond.) To get // the type of the constructor argument, take the generic // type definition IEnumerable<T> (expressed as // IEnumerable<> when you use the typeof operator) and // call MakeGenericType with the first generic type parameter // of List<T>. The constructor argument list must be passed // as an array, with just one argument in this case. // // Now it is possible to get the constructor of List<T>, // using GetConstructor on the generic type definition. To get // the constructor of List<TFirst>, pass List<TFirst> and // the constructor from List<T> to the static // TypeBuilder.GetConstructor method. // //<Snippet23> ILGenerator ilgen = exMethod.GetILGenerator(); Type ienumOf = typeof(IEnumerable <>); Type TfromListOf = listOf.GetGenericArguments()[0]; Type ienumOfT = ienumOf.MakeGenericType(TfromListOf); Type[] ctorArgs = { ienumOfT }; ConstructorInfo ctorPrep = listOf.GetConstructor(ctorArgs); ConstructorInfo ctor = TypeBuilder.GetConstructor(listOfTFirst, ctorPrep); ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Newobj, ctor); ilgen.Emit(OpCodes.Ret); //</Snippet23> // Create the type and save the assembly. //<Snippet8> Type finished = myType.CreateType(); myAssembly.Save(myAsmName.Name + ".dll"); //</Snippet8> // Invoke the method. // ExampleMethod is not generic, but the type it belongs to is // generic, so in order to get a MethodInfo that can be invoked // it is necessary to create a constructed type. The Example // class satisfies the constraints on TFirst, because it is a // reference type and has a default constructor. In order to // have a class that satisfies the constraints on TSecond, // this code example defines the ExampleDerived type. These // two types are passed to MakeGenericMethod to create the // constructed type. // //<Snippet9> Type[] typeArgs = { typeof(Example), typeof(ExampleDerived) }; Type constructed = finished.MakeGenericType(typeArgs); MethodInfo mi = constructed.GetMethod("ExampleMethod"); //</Snippet9> // Create an array of Example objects, as input to the generic // method. This array must be passed as the only element of an // array of arguments. The first argument of Invoke is // null, because ExampleMethod is static. Display the count // on the resulting List<Example>. // //<Snippet10> Example[] input = { new Example(), new Example() }; object[] arguments = { input }; List <Example> listX = (List <Example>)mi.Invoke(null, arguments); Console.WriteLine( "\nThere are {0} elements in the List<Example>.", listX.Count); //</Snippet10> DisplayGenericParameters(finished); }
public void SetGenericParameterAttributes(GenericParameterAttributes genericParameterAttributes) { _genericTypeParameterBuilder.SetGenericParameterAttributes(genericParameterAttributes); }
public void CreateGeneric() { //创建一个名“ReflectionTest”的动态程序集,这个程序集可以执行和保存。 AppDomain myDomain = AppDomain.CurrentDomain; AssemblyName assemblyName = new AssemblyName("ReflectionTest"); AssemblyBuilder assemblyBuilder = myDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); //在这个程序集中创建一个与程序集名相同的模块,接着创建一个类MyClass ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll"); TypeBuilder myType = moduleBuilder.DefineType("MyClass", TypeAttributes.Public); //创建类型参数名,将达到这样的效果:public MyClass<TParam1, TParam2> string[] tNames = { "TName1", "TName2" }; GenericTypeParameterBuilder[] gtps = myType.DefineGenericParameters(tNames); GenericTypeParameterBuilder tName1 = gtps[0]; GenericTypeParameterBuilder tName2 = gtps[1]; //为泛型添加约束,TName1将会被添加构造器约束和引用类型约束 tName1.SetGenericParameterAttributes(GenericParameterAttributes.DefaultConstructorConstraint | GenericParameterAttributes.ReferenceTypeConstraint); //TName2达到的效果将是:where TName2:ValueType,IComparable,IEnumerable Type baseType = typeof(BaseClass); Type interfaceA = typeof(IInterfaceA); Type interfaceB = typeof(IInterfaceB); Type[] interfaceTypes = { interfaceA, interfaceB }; tName2.SetBaseTypeConstraint(baseType); tName2.SetInterfaceConstraints(interfaceTypes); FieldBuilder fieldBuilder = myType.DefineField("name", typeof(string), FieldAttributes.Public); FieldBuilder fieldBuilder2 = myType.DefineField("tField1", tName1, FieldAttributes.Public); //为泛型类添加方法Hello Type listType = typeof(List <>); Type ReturnType = listType.MakeGenericType(tName1); Type[] parameter = { tName1.MakeArrayType() }; MethodBuilder methodBuilder = myType.DefineMethod("Hello", MethodAttributes.Public | MethodAttributes.Static, ReturnType, parameter); //为方法添加方法体 Type ienumof = typeof(IEnumerable <>); Type TFromListOf = listType.GetGenericArguments()[0]; Type ienumOfT = ienumof.MakeGenericType(TFromListOf); Type[] ctorArgs = { ienumOfT }; ConstructorInfo cInfo = listType.GetConstructor(ctorArgs); //最终的目的是要调用List<TName1>的构造函数:new List<TName1>(IEnumerable<TName1>); ConstructorInfo ctor = TypeBuilder.GetConstructor(ReturnType, cInfo); //设置IL指令 ILGenerator msil = methodBuilder.GetILGenerator(); msil.Emit(OpCodes.Ldarg_0); msil.Emit(OpCodes.Newobj, ctor); msil.Emit(OpCodes.Ret); //创建并保存程序集 Type finished = myType.CreateType(); assemblyBuilder.Save(assemblyName.Name + ".dll"); //创建这个MyClass类 Type[] typeArgs = { typeof(ClassT1), typeof(ClassT2) }; Type constructed = finished.MakeGenericType(typeArgs); object o = Activator.CreateInstance(constructed); MethodInfo mi = constructed.GetMethod("Hello"); ClassT1[] inputParameter = { new ClassT1(), new ClassT1() }; object[] arguments = { inputParameter }; List <ClassT1> listResult = (List <ClassT1>)mi.Invoke(null, arguments); //查看返回结果中的数量和完全限定名 Console.WriteLine(listResult.Count); Console.WriteLine(listResult[0].GetType().FullName); //查看类型参数以及约束 foreach (Type t in finished.GetGenericArguments()) { Console.WriteLine(t.ToString()); foreach (Type c in t.GetGenericParameterConstraints()) { Console.WriteLine(" " + c.ToString()); } } }
private void InitializeGenericParameters(DefineGenericParametersDelegate defineGenericParameters, GenericParameterCollection genericParameters) { if (genericParameters.Count == 0) { return; } string[] names = CollectionUtils.ConvertAllToArray <GenericParameter, string>(genericParameters, delegate(GenericParameter genericParameter) { return(genericParameter.Name); }); GenericTypeParameterBuilder[] genericTypeParameterBuilders = defineGenericParameters(names); for (int i = 0; i < genericParameters.Count; i++) { GenericTypeParameterBuilder genericTypeParameterBuilder = genericTypeParameterBuilders[i]; GenericParameter genericParameter = genericParameters[i]; genericTypeParameterBuilder.SetGenericParameterAttributes( (System.Reflection.GenericParameterAttributes)genericParameter.Attributes); if (genericParameter.Constraints.Count != 0) { Type classConstraint = null; List <Type> interfaceConstraints = new List <Type>(); foreach (TypeReference typeReference in genericParameter.Constraints) { Type type = ResolveType(typeReference); if (type.IsInterface) { interfaceConstraints.Add(type); } else { classConstraint = type; } } if (classConstraint != null) { genericTypeParameterBuilder.SetBaseTypeConstraint(classConstraint); } if (interfaceConstraints.Count != 0) { genericTypeParameterBuilder.SetInterfaceConstraints(interfaceConstraints.ToArray()); } } } metadataPass.Add(delegate { for (int i = 0; i < genericParameters.Count; i++) { InitializeCustomAttributes(genericTypeParameterBuilders[i].SetCustomAttribute, genericParameters[i].CustomAttributes); } }); }
private static void DefineMethodGenericConstraints(Type genericArgument, GenericTypeParameterBuilder typeParameter) { typeParameter.SetGenericParameterAttributes(genericArgument.GenericParameterAttributes); typeParameter.SetBaseTypeConstraint(genericArgument.BaseType); typeParameter.SetInterfaceConstraints(genericArgument.GetInterfaces()); }
/// <summary> /// Creates a proxy type of the specified source type. /// </summary> /// <param name="sourceType"></param> /// <returns></returns> protected virtual Type InternalCreateProxyType(Type sourceType) { // load virtual methods MethodInfo[] methods = sourceType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where((item) => // not constrcutor methods !item.IsConstructor && // only overridable methods this.IsMethodOverridable(item) && // ignore property methods and operator override method !item.IsSpecialName && // ignore marked methods item.GetCustomAttributes(typeof(FilterIgnoreAttribute), true).Length == 0 && // ignore common methods defined in System.Object class !item.DeclaringType.Equals(typeof(object))).ToArray(); // load virtual properties PropertyInfo[] properties = sourceType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where((item) => // ignore index properties item.GetIndexParameters().Length == 0 && // can read or write (item.CanRead || item.CanWrite) && // ignore special properties !item.IsSpecialName && // ignore marked methods Attribute.GetCustomAttributes(item, typeof(FilterIgnoreAttribute), true).Length == 0 && // ignore common properties defined in System.Object class !item.DeclaringType.Equals(typeof(object))).ToArray(); // find class filters MethodFilterAttribute[] classFilters = sourceType.GetCustomAttributes(typeof(MethodFilterAttribute), true).Cast <MethodFilterAttribute>().OrderBy((item) => item.Order).ToArray(); // find methods filters MethodFilterAttribute[][] methodFilters = new MethodFilterAttribute[methods.Length][]; for (int i = 0; i < methods.Length; i++) { methodFilters[i] = methods[i].GetCustomAttributes(typeof(MethodFilterAttribute), true).Cast <MethodFilterAttribute>().OrderBy((item) => item.Order).ToArray(); } // find properties filters MethodFilterAttribute[][] propertyFilters = new MethodFilterAttribute[properties.Length][]; for (int i = 0; i < properties.Length; i++) { propertyFilters[i] = Attribute.GetCustomAttributes(properties[i], typeof(MethodFilterAttribute), true).Cast <MethodFilterAttribute>().OrderBy((item) => item.Order).ToArray(); } if (methods.Length == 0 && properties.Length == 0 || classFilters.Length == 0 && methodFilters.All((item) => item.Length == 0) && propertyFilters.All((item) => item.Length == 0)) { return(sourceType); } ILGenerator generator = null; #region Create Proxy Type TypeAttributes typeAttributes = sourceType.Attributes; typeAttributes &= ~(TypeAttributes.NestedPrivate | TypeAttributes.NestedPublic | TypeAttributes.NestedFamily | TypeAttributes.NestedAssembly | TypeAttributes.NestedFamANDAssem | TypeAttributes.NestedFamORAssem); typeAttributes |= TypeAttributes.Public; Type typeParameter = null; Type[] typeParameters = null; GenericTypeParameterBuilder typeParameterBuilder = null; GenericTypeParameterBuilder[] typeParameterBuilders = null; TypeBuilder typeBuilder = this.m_moduleBuilder.DefineType(this.GetProxyTypeName(sourceType), typeAttributes, sourceType); this.InjectCustomAttributes(sourceType, typeBuilder); // create type arguments if (sourceType.IsGenericTypeDefinition || sourceType.IsGenericType && sourceType.ContainsGenericParameters) { typeParameters = sourceType.GetGenericArguments().Where((item) => item.IsGenericParameter).ToArray(); if (typeParameters.Length > 0) { typeParameterBuilders = typeBuilder.DefineGenericParameters(typeParameters.Select((item) => item.Name).ToArray()); for (int j = 0; j < typeParameters.Length; j++) { typeParameter = typeParameters[j]; typeParameterBuilder = typeParameterBuilders[j]; typeParameterBuilder.SetGenericParameterAttributes(typeParameter.GenericParameterAttributes); foreach (Type constraint in typeParameter.GetGenericParameterConstraints()) { if (constraint.IsClass) { typeParameterBuilder.SetBaseTypeConstraint(constraint); } else { typeParameterBuilder.SetInterfaceConstraints(constraint); } } } } } #endregion #region Create Static Fields int filterIndex = 0; FieldBuilder[] staticFields = new FieldBuilder[classFilters.Length + methodFilters.Sum((item) => item.Length) + propertyFilters.Sum((item) => item.Length)]; for (int i = 0; i < classFilters.Length; i++, filterIndex++) { staticFields[filterIndex] = typeBuilder.DefineField(this.GetStaticFieldName(filterIndex), typeof(IMethodFilter), FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly); } for (int i = 0; i < methods.Length; i++) { if (methodFilters[i].Length == 0) { continue; } for (int j = 0; j < methodFilters[i].Length; j++, filterIndex++) { staticFields[filterIndex] = typeBuilder.DefineField(this.GetStaticFieldName(filterIndex), typeof(IMethodFilter), FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly); } } for (int i = 0; i < properties.Length; i++) { if (propertyFilters[i].Length == 0) { continue; } for (int j = 0; j < propertyFilters[i].Length; j++, filterIndex++) { staticFields[filterIndex] = typeBuilder.DefineField(this.GetStaticFieldName(filterIndex), typeof(IMethodFilter), FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly); } } #endregion #region Create Static Constructor string classKey = this.GetClassKey(sourceType, typeBuilder); IMethodFilter[] filters = g_classFilters[classKey] = new IMethodFilter[staticFields.Length]; ConstructorBuilder constructorBuilder = typeBuilder.DefineTypeInitializer(); generator = constructorBuilder.GetILGenerator(); for (int i = 0; i < classFilters.Length; i++) { filters[i] = classFilters[i]; generator.Emit(OpCodes.Ldstr, classKey); generator.Emit(OpCodes.Ldc_I4, i); generator.Emit(OpCodes.Call, g_getClassFilterMethod); generator.Emit(OpCodes.Stsfld, staticFields[i]); } filterIndex = classFilters.Length; for (int i = 0; i < methods.Length; i++) { if (methodFilters[i].Length == 0) { continue; } for (int j = 0; j < methodFilters[i].Length; j++, filterIndex++) { filters[filterIndex] = methodFilters[i][j]; generator.Emit(OpCodes.Ldstr, classKey); generator.Emit(OpCodes.Ldc_I4, filterIndex); generator.Emit(OpCodes.Call, g_getClassFilterMethod); generator.Emit(OpCodes.Stsfld, staticFields[filterIndex]); } } for (int i = 0; i < properties.Length; i++) { if (propertyFilters[i].Length == 0) { continue; } for (int j = 0; j < propertyFilters[i].Length; j++, filterIndex++) { filters[filterIndex] = propertyFilters[i][j]; generator.Emit(OpCodes.Ldstr, classKey); generator.Emit(OpCodes.Ldc_I4, filterIndex); generator.Emit(OpCodes.Call, g_getClassFilterMethod); generator.Emit(OpCodes.Stsfld, staticFields[filterIndex]); } } generator.Emit(OpCodes.Ret); #endregion #region Create Instance Constructors ParameterInfo[] constructorParameters = null; foreach (ConstructorInfo constructor in sourceType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { constructorParameters = constructor.GetParameters(); constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, constructorParameters.Select((item) => item.ParameterType).ToArray()); for (int i = 0; i < constructorParameters.Length; i++) { this.InjectCustomAttributes( constructorParameters[i], constructorBuilder.DefineParameter(i + 1, constructorParameters[i].Attributes, constructorParameters[i].Name)); } generator = constructorBuilder.GetILGenerator(); // call base constructor generator.Emit(OpCodes.Ldarg_0); for (int i = 1; i <= constructorParameters.Length; i++) { generator.Emit(OpCodes.Ldarg, i); } generator.Emit(OpCodes.Call, constructor); generator.Emit(OpCodes.Ret); } #endregion #region Create Methods filterIndex = classFilters.Length; for (int i = 0; i < methods.Length; i++) { if (methodFilters[i].Length + classFilters.Length == 0) { continue; } this.CreateProxyMethod(typeBuilder, methods[i], classFilters, methodFilters[i], staticFields, filterIndex, (item) => true); filterIndex += methodFilters[i].Length; } PropertyInfo property = null; PropertyBuilder propertyBuilder = null; MethodInfo getMethod = null, setMethod = null; bool isGetMethodOverridable = false, isSetMethodOverridable = false; bool isPropertyFilterGetMethod = false, isPropertyFilterSetMethod = false; bool isClassFilterGetMethod = classFilters.Any((item) => item.PropertyMethods.HasFlag(MethodFilterActOnPropertyMethods.GetMethod)); bool isClassFilterSetMethod = classFilters.Any((item) => item.PropertyMethods.HasFlag(MethodFilterActOnPropertyMethods.SetMethod)); for (int i = 0; i < properties.Length; i++) { if (propertyFilters[i].Length + classFilters.Length == 0) { continue; } property = properties[i]; isPropertyFilterGetMethod = propertyFilters[i].Any((item) => item.PropertyMethods.HasFlag(MethodFilterActOnPropertyMethods.GetMethod)); isPropertyFilterSetMethod = propertyFilters[i].Any((item) => item.PropertyMethods.HasFlag(MethodFilterActOnPropertyMethods.SetMethod)); isGetMethodOverridable = this.IsMethodOverridable(getMethod = property.GetGetMethod(true)) && (isClassFilterGetMethod || isPropertyFilterGetMethod); isSetMethodOverridable = this.IsMethodOverridable(setMethod = property.GetSetMethod(true)) && (isClassFilterSetMethod || isPropertyFilterSetMethod); if (!isGetMethodOverridable && !isSetMethodOverridable) { continue; } propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, null); if (isGetMethodOverridable) { propertyBuilder.SetGetMethod(this.CreateProxyMethod(typeBuilder, getMethod, classFilters, propertyFilters[i], staticFields, filterIndex, (item) => item.PropertyMethods.HasFlag(MethodFilterActOnPropertyMethods.GetMethod))); } if (isSetMethodOverridable) { propertyBuilder.SetSetMethod(this.CreateProxyMethod(typeBuilder, setMethod, classFilters, propertyFilters[i], staticFields, filterIndex, (item) => item.PropertyMethods.HasFlag(MethodFilterActOnPropertyMethods.SetMethod))); } filterIndex += propertyFilters[i].Length; } #endregion return(typeBuilder.CreateType()); }
protected virtual MethodBuilder CreateProxyMethod(TypeBuilder typeBuilder, MethodInfo method, MethodFilterAttribute[] classFilters, MethodFilterAttribute[] methodFilters, FieldBuilder[] staticFields, int startFilterIndex, Func <MethodFilterAttribute, bool> predicate) { ILGenerator generator = null; Type typeParameter = null; Type[] typeParameters = null; GenericTypeParameterBuilder typeParameterBuilder = null; GenericTypeParameterBuilder[] typeParameterBuilders = null; MethodBuilder methodBuilder = null; ParameterInfo methodParameter = null; ParameterInfo[] methodParameters = method.GetParameters(); LocalBuilder contextVariableBuilder = null, exceptionVariableBuilder = null, returnVariableBuilder = null; Label checkCancelLabel, callBaseMethodLabel; // create method MethodAttributes methodAttributes = (method.IsPublic ? MethodAttributes.Public : MethodAttributes.Family) | MethodAttributes.Virtual; if (method.IsSpecialName) { methodAttributes |= MethodAttributes.SpecialName; } methodBuilder = typeBuilder.DefineMethod(method.Name, methodAttributes, CallingConventions.Standard, method.ReturnType, methodParameters.Select((item) => item.ParameterType).ToArray()); this.InjectCustomAttributes(method, methodBuilder); // create method type arguments if (method.IsGenericMethodDefinition || method.IsGenericMethod && method.ContainsGenericParameters) { typeParameters = method.GetGenericArguments().Where((item) => item.IsGenericParameter).ToArray(); if (typeParameters.Length > 0) { typeParameterBuilders = methodBuilder.DefineGenericParameters(typeParameters.Select((item) => item.Name).ToArray()); for (int j = 0; j < typeParameters.Length; j++) { typeParameter = typeParameters[j]; typeParameterBuilder = typeParameterBuilders[j]; typeParameterBuilder.SetGenericParameterAttributes(typeParameter.GenericParameterAttributes); foreach (Type constraint in typeParameter.GetGenericParameterConstraints()) { if (constraint.IsClass) { typeParameterBuilder.SetBaseTypeConstraint(constraint); } else { typeParameterBuilder.SetInterfaceConstraints(constraint); } } } } } // create method parameters for (int j = 0; j < methodParameters.Length; j++) { this.InjectCustomAttributes( methodParameters[j], methodBuilder.DefineParameter(j + 1, methodParameters[j].Attributes, methodParameters[j].Name)); } // delcare local variables generator = methodBuilder.GetILGenerator(); contextVariableBuilder = generator.DeclareLocal(typeof(MethodExecutingContext), false); exceptionVariableBuilder = generator.DeclareLocal(typeof(Exception), false); if (!method.ReturnType.Equals(typeof(void))) { returnVariableBuilder = generator.DeclareLocal(method.ReturnType, false); } // initialize local variables generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldstr, method.ReflectedType.FullName); generator.Emit(OpCodes.Ldstr, method.Name); generator.Emit(OpCodes.Ldstr, method.ToString()); generator.Emit(OpCodes.Newobj, g_contextConstructor); generator.Emit(OpCodes.Stloc_0); // initialize arguments of context variable for (int j = 0; j < methodParameters.Length; j++) { if ((methodParameter = methodParameters[j]).IsOut) { continue; } generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldstr, methodParameter.Name); generator.Emit(OpCodes.Ldarg, j + 1); if (methodParameter.ParameterType.IsValueType) { generator.Emit(OpCodes.Box, methodParameter.ParameterType); } generator.Emit(OpCodes.Callvirt, g_contextAddArgumentMethod); } // invoke OnPreExecuting for (int j = 0; j < classFilters.Length; j++) { if (!predicate(classFilters[j])) { continue; } generator.Emit(OpCodes.Ldsfld, staticFields[j]); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Callvirt, g_onPreExecutingMethod); } for (int j = 0; j < methodFilters.Length; j++) { if (!predicate(methodFilters[j])) { continue; } generator.Emit(OpCodes.Ldsfld, staticFields[startFilterIndex + j]); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Callvirt, g_onPreExecutingMethod); } // check Exception property generator.BeginExceptionBlock(); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Callvirt, g_contextExceptionGetter); generator.Emit(OpCodes.Brfalse_S, checkCancelLabel = generator.DefineLabel()); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Callvirt, g_contextExceptionGetter); generator.Emit(OpCodes.Throw); // check IsCancel property generator.MarkLabel(checkCancelLabel); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Callvirt, g_contextIsCancelGetter); generator.Emit(OpCodes.Brfalse_S, callBaseMethodLabel = generator.DefineLabel()); generator.Emit(OpCodes.Newobj, g_canceledExceptionConstructor); generator.Emit(OpCodes.Throw); // call current method generator.BeginExceptionBlock(); generator.MarkLabel(callBaseMethodLabel); generator.Emit(OpCodes.Ldarg_0); for (int j = 1; j <= methodParameters.Length; j++) { generator.Emit(OpCodes.Ldarg, j); } generator.Emit(OpCodes.Call, method); if (!method.ReturnType.Equals(typeof(void))) { generator.Emit(OpCodes.Stloc_2); } // catch Exception generator.BeginCatchBlock(typeof(Exception)); generator.Emit(OpCodes.Stloc_1); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Callvirt, g_contextExceptionSetter); generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Throw); generator.EndExceptionBlock(); // invoke OnPostExecuting generator.BeginFinallyBlock(); for (int j = 0; j < methodFilters.Length; j++) { if (!predicate(methodFilters[j])) { continue; } generator.Emit(OpCodes.Ldsfld, staticFields[startFilterIndex + j]); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Callvirt, g_onPostExecutingMethod); } for (int j = 0; j < classFilters.Length; j++) { if (!predicate(classFilters[j])) { continue; } generator.Emit(OpCodes.Ldsfld, staticFields[j]); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Callvirt, g_onPostExecutingMethod); } generator.EndExceptionBlock(); if (!method.ReturnType.Equals(typeof(void))) { generator.Emit(OpCodes.Ldloc_2); } generator.Emit(OpCodes.Ret); return(methodBuilder); }