Exemplo n.º 1
0
        public void IsArray()
        {
            GenericTypeParameterBuilder typeParam = Helpers.DynamicType(TypeAttributes.Public).DefineGenericParameters("TFirst")[0];

            Assert.False(typeParam.IsArray);
            Assert.False(typeParam.IsSZArray);

            Type asType = typeParam.AsType();

            Assert.False(asType.IsArray);
            Assert.False(asType.IsSZArray);

            Type arrType = typeParam.MakeArrayType();

            Assert.True(arrType.IsArray);
            Assert.True(arrType.IsSZArray);

            arrType = typeParam.MakeArrayType(1);
            Assert.True(arrType.IsArray);
            Assert.False(arrType.IsSZArray);

            arrType = typeParam.MakeArrayType(2);
            Assert.True(arrType.IsArray);
            Assert.False(arrType.IsSZArray);
        }
Exemplo n.º 2
0
        private static PropertyBuilder GetPropertyBuilder_Cell(TypeBuilder tb, GenericTypeParameterBuilder K, FieldBuilder fb_cell)
        {
            PropertyBuilder pb_Cell = tb.DefineProperty("Cell", PropertyAttributes.HasDefault, K.MakeArrayType(), null);

            MethodBuilder cellGetter = tb.DefineMethod(
                "get_Cell",
                MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual,
                K.MakeArrayType(),
                Type.EmptyTypes);

            ILGenerator cellGetterIL = cellGetter.GetILGenerator();

            cellGetterIL.Emit(OpCodes.Ldarg_0);
            cellGetterIL.Emit(OpCodes.Ldfld, fb_cell);
            cellGetterIL.Emit(OpCodes.Ret);

            MethodBuilder cellSetter = tb.DefineMethod(
                "set_Cell",
                MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual,
                null,
                new Type[] { K.MakeArrayType() });

            ILGenerator cellSetterIL = cellSetter.GetILGenerator();

            cellSetterIL.Emit(OpCodes.Ldarg_0);
            cellSetterIL.Emit(OpCodes.Ldarg_1);
            cellSetterIL.Emit(OpCodes.Stfld, fb_cell);
            cellSetterIL.Emit(OpCodes.Ret);

            pb_Cell.SetGetMethod(cellGetter);
            pb_Cell.SetSetMethod(cellSetter);
            return(pb_Cell);
        }
        private static void BuildGenericType()
        {
            //Define assembly
            AppDomain       dom     = AppDomain.CurrentDomain;
            AssemblyName    asmName = new AssemblyName("domath");
            AssemblyBuilder asm     = dom.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);

            //Define a dynamic module
            ModuleBuilder mod = asm.DefineDynamicModule(asmName.Name, asmName.Name + ".dll");

            //Define a class
            TypeBuilder asmType = mod.DefineType("OurClass", TypeAttributes.Public);

            //Define the generic type parameters
            string[] typeNames = { "TFirst", "TSecond" };
            GenericTypeParameterBuilder[] genTypes = asmType.DefineGenericParameters(typeNames);

            GenericTypeParameterBuilder TFirst  = genTypes[0];
            GenericTypeParameterBuilder TSecond = genTypes[1];

            //Define generic constraints
            TFirst.SetGenericParameterAttributes(GenericParameterAttributes.DefaultConstructorConstraint | GenericParameterAttributes.ReferenceTypeConstraint);
            TSecond.SetBaseTypeConstraint(typeof(SomeBaseClass));

            Type[] interfaceTypes = { typeof(InterfaceA), typeof(InterfaceB) };
            TSecond.SetInterfaceConstraints(interfaceTypes);

            //Define a field
            FieldBuilder fld1 = asmType.DefineField("Field1", TFirst, FieldAttributes.Private);

            //Define method
            Type listOf       = typeof(List <>);
            Type listOfTFirst = listOf.MakeGenericType(TFirst);

            Type[] paramTypes = { TFirst.MakeArrayType() };

            MethodBuilder asmMethod = asmType.DefineMethod("SomeMethod", MethodAttributes.Public | MethodAttributes.Static, listOfTFirst, paramTypes);

            //Define Method Body
            ILGenerator il = asmMethod.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);

            il.Emit(OpCodes.Ldarg_0);      //Loads the argument at index 0 onto the evaluation stack.
            il.Emit(OpCodes.Newobj, ctor); //Creates a new object or a new instance of a value type, pushing an object reference (type O) onto the evaluation stack.
            il.Emit(OpCodes.Ret);          //Returns from the current method, pushing a return value (if present) from the callee's evaluation stack onto the caller's evaluation stack.

            //Create type and save file
            Type finished = asmType.CreateType();

            asm.Save(asmName.Name + ".dll");
        }
        public void TestThrowsExceptionForNegativeRank()
        {
            AssemblyName    myAsmName  = new AssemblyName("GenericEmitExample1");
            AssemblyBuilder myAssembly = AssemblyBuilder.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.Run);
            ModuleBuilder   myModule   = TestLibrary.Utilities.GetModuleBuilder(myAssembly, myAsmName.Name);

            Type baseType = typeof(ExampleBase);

            TypeBuilder myType = myModule.DefineType("Sample", TypeAttributes.Public);

            string[] typeParamNames = { "TFirst" };
            GenericTypeParameterBuilder[] typeParams = myType.DefineGenericParameters(typeParamNames);

            GenericTypeParameterBuilder TFirst = typeParams[0];

            Assert.Throws <IndexOutOfRangeException>(() => { Type type = TFirst.MakeArrayType(-1); });
        }
        public void TestWithRankOne()
        {
            AssemblyName    myAsmName  = new AssemblyName("GenericEmitExample1");
            AssemblyBuilder myAssembly = AssemblyBuilder.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.Run);
            ModuleBuilder   myModule   = TestLibrary.Utilities.GetModuleBuilder(myAssembly, myAsmName.Name);

            Type baseType = typeof(ExampleBase);

            TypeBuilder myType = myModule.DefineType("Sample", TypeAttributes.Public);

            string[] typeParamNames = { "TFirst" };
            GenericTypeParameterBuilder[] typeParams = myType.DefineGenericParameters(typeParamNames);

            GenericTypeParameterBuilder TFirst = typeParams[0];
            string expectedValue = "TFirst[*]";
            string actualValue;

            Type type = TFirst.MakeArrayType(1);

            actualValue = type.Name;

            Assert.Equal(expectedValue, actualValue);
        }
        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]);
        }
Exemplo n.º 7
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);
    }
Exemplo n.º 8
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());
                }
            }
        }