Export (0) Print
Expand All
1 out of 1 rated this helpful - Rate this topic

GenericTypeParameterBuilder Class

Note: This class is new in the .NET Framework version 2.0.

Defines and creates generic type parameters for dynamically defined generic types and methods. This class cannot be inherited.

Namespace: System.Reflection.Emit
Assembly: mscorlib (in mscorlib.dll)

[ComVisibleAttribute(true)] 
public sealed class GenericTypeParameterBuilder : Type
/** @attribute ComVisibleAttribute(true) */ 
public final class GenericTypeParameterBuilder extends Type
ComVisibleAttribute(true) 
public final class GenericTypeParameterBuilder extends Type

You can get an array of GenericTypeParameterBuilder objects by using the TypeBuilder.DefineGenericParameters method to add type parameters to a dynamic type, thus making it a generic type, or by using the MethodBuilder.DefineGenericParameters method to add type parameters to a dynamic method. Use the GenericTypeParameterBuilder objects to add constraints to the type parameters. Constraints are of three kinds:

  • The base type constraint specifies that any type assigned to the generic type parameter must derive from a particular base type. Set this constraint by using the SetBaseTypeConstraint method.

  • An interface constraint specifies that any type assigned to the generic type parameter must implement a particular interface. Set the interface constraints by using the SetInterfaceConstraints method.

  • Special constraints specify that any type assigned to the generic type parameter must have a default constructor, must be a reference type, or must be a value type. Set the special constraints for a type parameter by using the SetGenericParameterAttributes method.

Interface constraints and special constraints cannot be retrieved using methods of the GenericTypeParameterBuilder class. Once you have created the generic type that contains the type parameters, you can use its Type object to reflect the constraints. Use the Type.GetGenericArguments method to get the type parameters, and for each type parameter use the Type.GetGenericParameterConstraints method to get the base type constraint and interface constraints, and the Type.GenericParameterAttributes property to get the special constraints.

The following code example creates a generic type with two type parameters, and saves them in the assembly GenericEmitExample1.dll. You can use the MSIL Disassembler (Ildasm.exe) to view the generated types. For a more detailed explanation of the steps involved in defining a dynamic generic type, see How to: Define a Generic Type with Reflection Emit.

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

// Define a trivial base class and two trivial interfaces 
// to use when demonstrating constraints.
//
public class ExampleBase {}

public interface IExampleA {}

public interface IExampleB {}

// Define a trivial type that can substitute for type parameter 
// TSecond.
//
public class ExampleDerived : ExampleBase, IExampleA, IExampleB {}


public class Example
{
    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.
        //
        AppDomain myDomain = AppDomain.CurrentDomain;
        AssemblyName myAsmName = new AssemblyName("GenericEmitExample1");
        AssemblyBuilder myAssembly = 
            myDomain.DefineDynamicAssembly(myAsmName, 
                AssemblyBuilderAccess.RunAndSave);

        // 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. 
        //
        ModuleBuilder myModule = 
            myAssembly.DefineDynamicModule(myAsmName.Name, 
               myAsmName.Name + ".dll");

        // 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.
        //
        TypeBuilder myType = 
            myModule.DefineType("Sample", TypeAttributes.Public);

        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.
        // 
        string[] typeParamNames = {"TFirst", "TSecond"};
        GenericTypeParameterBuilder[] typeParams = 
            myType.DefineGenericParameters(typeParamNames);

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

        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.
        TFirst.SetGenericParameterAttributes(
            GenericParameterAttributes.DefaultConstructorConstraint |
            GenericParameterAttributes.ReferenceTypeConstraint);

        // 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.
        TSecond.SetBaseTypeConstraint(baseType);
        Type[] interfaceTypes = {interfaceA, interfaceB};
        TSecond.SetInterfaceConstraints(interfaceTypes);

        // The following code adds a private field named ExampleField,
        // of type TFirst.
        FieldBuilder exField = 
            myType.DefineField("ExampleField", TFirst, 
                FieldAttributes.Private);

        // 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. 
        //
        Type listOf = typeof(List<>);
        Type listOfTFirst = listOf.MakeGenericType(TFirst);
        Type[] mParamTypes = {TFirst.MakeArrayType()};

        MethodBuilder exMethod = 
            myType.DefineMethod("ExampleMethod", 
                MethodAttributes.Public | MethodAttributes.Static, 
                listOfTFirst, 
                mParamTypes);

        // 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.
        //
        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);

        // Create the type and save the assembly. 
        Type finished = myType.CreateType();
        myAssembly.Save(myAsmName.Name+".dll");

        // 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.
        //
        Type[] typeArgs = {typeof(Example), typeof(ExampleDerived)};
        Type constructed = finished.MakeGenericType(typeArgs);
        MethodInfo mi = constructed.GetMethod("ExampleMethod");

        // 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>.
        // 
        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);

        DisplayGenericParameters(finished);
    }

    private static void DisplayGenericParameters(Type t)
    {
        if (!t.IsGenericType)
        {
            Console.WriteLine("Type '{0}' is not generic.");
            return;
        }
        if (!t.IsGenericTypeDefinition) 
        {
            t = t.GetGenericTypeDefinition();
        }

        Type[] typeParameters = t.GetGenericArguments();
        Console.WriteLine("\nListing {0} type parameters for type '{1}'.",
            typeParameters.Length, t);

        foreach( Type tParam in typeParameters )
        {
            Console.WriteLine("\r\nType parameter {0}:", tParam.ToString());

            foreach( Type c in tParam.GetGenericParameterConstraints() )
            {
                if (c.IsInterface)
                {
                    Console.WriteLine("    Interface constraint: {0}", c);
                }
                else
                {
                    Console.WriteLine("    Base type constraint: {0}", c);
                }
            }

            ListConstraintAttributes(tParam);
        }
    }

    // List the constraint flags. The GenericParameterAttributes
    // enumeration contains two sets of attributes, variance and
    // constraints. For this example, only constraints are used.
    //
    private static void ListConstraintAttributes(Type t)
    {
        // Mask off the constraint flags. 
        GenericParameterAttributes constraints = 
            t.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;

        if ((constraints & GenericParameterAttributes.ReferenceTypeConstraint)
            != GenericParameterAttributes.None) 
        {
            Console.WriteLine("    ReferenceTypeConstraint");
        }

        if ((constraints & GenericParameterAttributes.NotNullableValueTypeConstraint)
            != GenericParameterAttributes.None) 
        {
            Console.WriteLine("    NotNullableValueTypeConstraint");
        }

        if ((constraints & GenericParameterAttributes.DefaultConstructorConstraint)
            !=GenericParameterAttributes.None) 
        {
            Console.WriteLine("    DefaultConstructorConstraint");
        }
    }
}

/* This code example produces the following output:

Type 'Sample' is generic: False
Type 'Sample' is generic: True

There are 2 elements in the List<Example>.

Listing 2 type parameters for type 'Sample[TFirst,TSecond]'.

Type parameter TFirst:
    ReferenceTypeConstraint
    DefaultConstructorConstraint

Type parameter TSecond:
    Interface constraint: IExampleA
    Interface constraint: IExampleB
    Base type constraint: ExampleBase
 */

System.Object
   System.Reflection.MemberInfo
     System.Type
      System.Reflection.Emit.GenericTypeParameterBuilder
Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

Windows 98, Windows 2000 SP4, Windows Millennium Edition, Windows Server 2003, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP SP2, Windows XP Starter Edition

The .NET Framework does not support all versions of every platform. For a list of the supported versions, see System Requirements.

.NET Framework

Supported in: 2.0
Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback

Community Additions

ADD
Show:
© 2014 Microsoft. All rights reserved.