예제 #1
0
                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]);
        }
예제 #4
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);
 }
예제 #6
0
        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);
                }
            });
        }
예제 #8
0
 private static void DefineMethodGenericConstraints(Type genericArgument, GenericTypeParameterBuilder typeParameter)
 {
     typeParameter.SetGenericParameterAttributes(genericArgument.GenericParameterAttributes);
     typeParameter.SetBaseTypeConstraint(genericArgument.BaseType);
     typeParameter.SetInterfaceConstraints(genericArgument.GetInterfaces());
 }
예제 #9
0
        /// <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());
        }
예제 #10
0
        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);
        }