使用反射检查和实例化泛型类型(转自:http://www.csharpwin.com/csharpspace/12241r3312.shtml)

与其他类型的信息一样,泛型类型的信息的获取方式为:检查表示泛型类型的 Type 对象。主要的差异在于,泛型类型具有一组表示其泛型类型参数的 Type 对象。本部分的第一个步骤是检查泛型类型。

通过将类型变量绑定到泛型类型定义的类型参数,可以创建表示构造类型的 Type 对象。第二个步骤演示此过程。

检查泛型类型及其类型参数

  1. 获取表示泛型类型的 Type 实例。在下面的代码中,使用 C# 的 typeof 运算符(在 Visual Basic 中为GetType,在 Visual C++ 中为 typeid)获取类型。有关获取 Type 对象的其他方法,请参见 Type 类主题。注意,余下的步骤中,类型包含在名为 t 的方法参数中。

    C#

    Type d1 =  typeof(Dictionary<,>);

     
  2. 使用 IsGenericType 属性确定类型是否为泛型,然后使用 IsGenericTypeDefinition 属性确定类型是否为泛型类型定义。

    C#

    Console.WriteLine( "   Is this a generic type? {0}",
        t.IsGenericType);
    Console.WriteLine( " Is this a generic type definition? {0}",
        t.IsGenericTypeDefinition);

     
  3. 使用 GetGenericArguments 方法获取包含泛型类型参数的数组。

    C#

    Type[] typeParameters = t.GetGenericArguments();

     
  4. 对每个类型变量,使用 IsGenericParameter 属性确定其是不是类型参数(例如,在泛型类型定义中),是不是已为类型参数指定的类型(例如,在构造类型中)。

    C#

    Console.WriteLine( "   List {0} type arguments:", 
        typeParameters.Length);
    foreach( Type tParam  in typeParameters )
    {
         if (tParam.IsGenericParameter)
        {
            DisplayGenericParameter(tParam);
        }
         else
        {
            Console.WriteLine( "      Type argument: {0}",
                tParam);
        }
    }

     
  5. 在类型系统中,和普通类型一样,泛型类型参数是由 Type 的实例表示的。下面的代码演示表示泛型类型参数的 Type 对象的名称和参数位置。此处,参数位置无足轻重;它在检查类型参数(用作其他泛型类型的类型变量)时更有价值。

    C#

    private  static  void DisplayGenericParameter(Type tp)
    {
        Console.WriteLine( "      Type parameter: {0} position {1}", 
            tp.Name, tp.GenericParameterPosition);

     
  6. 通过使用 GetGenericParameterConstraints 方法获取单个数组中的所有约束,确定泛型类型参数的基类型约束和接口约束。不保证约束处于任何特定顺序。

    C#

    Type classConstraint =  null;

    foreach(Type iConstraint  in tp.GetGenericParameterConstraints())
    {
         if (iConstraint.IsInterface)
        {
            Console.WriteLine( "         Interface constraint: {0}",
                iConstraint);
        }
    }

    if (classConstraint !=  null)
    {
        Console.WriteLine( "         Base type constraint: {0}", 
            tp.BaseType);
    }
    else
        Console.WriteLine( "         Base type constraint: None"); 

     
  7. 使用 GenericParameterAttributes 属性获取类型参数的特殊约束,如要求其为引用类型。该属性还包含表示方差的值,该值可屏蔽,如下面的代码所示。

    C#

    GenericParameterAttributes sConstraints = 
        tp.GenericParameterAttributes & 
        GenericParameterAttributes.SpecialConstraintMask;

     
  8. 特殊约束的属性为标志,表示没有任何特殊约束的标志 (System.Reflection.GenericParameterAttributes.None) 还表示没有协变或逆变。因此,若要测试其中一个条件,必须使用适当的屏蔽。在此情况下,请使用 System.Reflection.GenericParameterAttributes.SpecialConstraintMask 隔离特殊约束标志。

    C#

    if (sConstraints == GenericParameterAttributes.None)
    {
        Console.WriteLine( "         No special constraints.");
    }
    else
    {
         if (GenericParameterAttributes.None != (sConstraints &
            GenericParameterAttributes.DefaultConstructorConstraint))
        {
            Console.WriteLine( "         Must have a parameterless constructor.");
        }
         if (GenericParameterAttributes.None != (sConstraints &
            GenericParameterAttributes.ReferenceTypeConstraint))
        {
            Console.WriteLine( "         Must be a reference type.");
        }
         if (GenericParameterAttributes.None != (sConstraints &
            GenericParameterAttributes.NotNullableValueTypeConstraint))
        {
            Console.WriteLine( "         Must be a non-nullable value type.");
        }
    }

     

构造泛型类型的实例

泛型类型和模板类似。除非指定其泛型类型参数的实际类型,否则不能创建泛型类型的实例。若要在运行时使用反射创建实例,需要使用 MakeGenericType 方法。

构造泛型类型的实例

  1. 获取表示泛型类型的 Type 对象。下面的代码以两种不同方式获取泛型类型 Dictionary:一种方法使用 System.Type.GetType(System.String) 方法重载和描述类型的字符串,另一种方法调用构造类型 Dictionary<String, Example>(在 Visual Basic 中为 Dictionary(Of String, Example))的 GetGenericTypeDefinition 方法。MakeGenericType 方法需要泛型类型定义。

    C#

    // Use the typeof operator to create the generic type 
    // definition directly. To specify the generic type definition,
    // omit the type arguments but retain the comma that separates
    // them.
    Type d1 =  typeof(Dictionary<,>);

    // You can also obtain the generic type definition from a
    // constructed class. In this case, the constructed class
    // is a dictionary of Example objects, with String keys.
    Dictionary< string, Example> d2 =  new Dictionary< string, Example>();
    // Get a Type object that represents the constructed type,
    // and from that get the generic type definition. The 
    // variables d1 and d4 contain the same type.
    Type d3 = d2.GetType();
    Type d4 = d3.GetGenericTypeDefinition();

     
  2. 构造一组用于替换类型参数的类型变量。数组必须包含正确数目的 Type 对象,并且顺序和对象在类型参数列表中的顺序相同。在这种情况下,键(第一个类型参数)的类型为 String,字典中的值是名为 Example 的类的实例。

    C#
     
    Type[] typeArgs = { typeof( string),  typeof(Example)};

     
  3. 调用 MakeGenericType 方法将类型变量绑定到类型参数,然后构造类型。

    C#
     
    Type constructed = d1.MakeGenericType(typeArgs);

     
  4. 使用 CreateInstance 方法重载来创建构造类型的对象。下面的代码在生成的 Dictionary<String, Example> 对象中存储 Example 类的两个实例。

    C#

    object o = Activator.CreateInstance(constructed);

     

示例

下面的代码示例定义 DisplayGenericType 方法来检查泛型类型定义和代码中使用的构造类型,并显示它们的信息。DisplayGenericType 方法演示如何使用 IsGenericTypeIsGenericParameter 和 GenericParameterPosition 属性以及 GetGenericArguments 方法。

该示例还定义 DisplayGenericParameter 方法来检查泛型类型参数并显示其约束。

代码示例定义一组测试类型,包括说明类型参数约束的泛型类型,并演示如何显示这些类型的信息。

示例通过创建一组类型参数并调用 MakeGenericType 方法,从 Dictionary 类构造类型。程序对使用 MakeGenericType 构造的 Type 对象和使用 typeof(Visual Basic 中为 GetType)获取的 Type 对象进行比较,演示这两个对象是相同的。类似地,程序使用 GetGenericTypeDefinition 方法获取构造类型的泛型类型定义,并将其与表示 Dictionary 类的 Type 对象进行比较。

 
C#
 
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Security.Permissions;

// Define an example interface.
public  interface ITestArgument {}

// Define an example base class.
public  class TestBase {}

// Define a generic class with one parameter. The parameter
// has three constraints: It must inherit TestBase, it must
// implement ITestArgument, and it must have a parameterless
// constructor.
public  class Test<T>  where T : TestBase, ITestArgument,  new() {}

// Define a class that meets the constraints on the type
// parameter of class Test.
public  class TestArgument : TestBase, ITestArgument
{
     public TestArgument() {}
}

public  class Example
{
     // The following method displays information about a generic
     // type.
     private  static  void DisplayGenericType(Type t)
    {
        Console.WriteLine( "/r/n {0}", t);
        Console.WriteLine( "   Is this a generic type? {0}",
            t.IsGenericType);
        Console.WriteLine( "   Is this a generic type definition? {0}",
            t.IsGenericTypeDefinition);

         // Get the generic type parameters or type arguments.
        Type[] typeParameters = t.GetGenericArguments();

        Console.WriteLine( "   List {0} type arguments:", 
            typeParameters.Length);
         foreach( Type tParam  in typeParameters )
        {
             if (tParam.IsGenericParameter)
            {
                DisplayGenericParameter(tParam);
            }
             else
            {
                Console.WriteLine( "      Type argument: {0}",
                    tParam);
            }
        }
    }

     // The following method displays information about a generic
     // type parameter. Generic type parameters are represented by
     // instances of System.Type, just like ordinary types.
     private  static  void DisplayGenericParameter(Type tp)
    {
        Console.WriteLine( "      Type parameter: {0} position {1}", 
            tp.Name, tp.GenericParameterPosition);

        Type classConstraint =  null;

         foreach(Type iConstraint  in tp.GetGenericParameterConstraints())
        {
             if (iConstraint.IsInterface)
            {
                Console.WriteLine( "         Interface constraint: {0}",
                    iConstraint);
            }
        }

         if (classConstraint !=  null)
        {
            Console.WriteLine( "         Base type constraint: {0}", 
                tp.BaseType);
        }
         else
            Console.WriteLine( "         Base type constraint: None"); 

        GenericParameterAttributes sConstraints = 
            tp.GenericParameterAttributes & 
            GenericParameterAttributes.SpecialConstraintMask;

         if (sConstraints == GenericParameterAttributes.None)
        {
            Console.WriteLine( "         No special constraints.");
        }
         else
        {
             if (GenericParameterAttributes.None != (sConstraints &
                GenericParameterAttributes.DefaultConstructorConstraint))
            {
                Console.WriteLine( "         Must have a parameterless constructor.");
            }
             if (GenericParameterAttributes.None != (sConstraints &
                GenericParameterAttributes.ReferenceTypeConstraint))
            {
                Console.WriteLine( "         Must be a reference type.");
            }
             if (GenericParameterAttributes.None != (sConstraints &
                GenericParameterAttributes.NotNullableValueTypeConstraint))
            {
                Console.WriteLine( "         Must be a non-nullable value type.");
            }
        }
    }

    [PermissionSetAttribute(SecurityAction.Demand, Name= "FullTrust")]
     public  static  void Main()
    {
         // Two ways to get a Type object that represents the generic
         // type definition of the Dictionary class. 
         //
         // Use the typeof operator to create the generic type 
         // definition directly. To specify the generic type definition,
         // omit the type arguments but retain the comma that separates
         // them.
        Type d1 =  typeof(Dictionary<,>);

         // You can also obtain the generic type definition from a
         // constructed class. In this case, the constructed class
         // is a dictionary of Example objects, with String keys.
        Dictionary< string, Example> d2 =  new Dictionary< string, Example>();
         // Get a Type object that represents the constructed type,
         // and from that get the generic type definition. The 
         // variables d1 and d4 contain the same type.
        Type d3 = d2.GetType();
        Type d4 = d3.GetGenericTypeDefinition();

         // Display information for the generic type definition, and
         // for the constructed type Dictionary<String, Example>.
        DisplayGenericType(d1);
        DisplayGenericType(d2.GetType());

         // Construct an array of type arguments to substitute for 
         // the type parameters of the generic Dictionary class.
         // The array must contain the correct number of types, in 
         // the same order that they appear in the type parameter 
         // list of Dictionary. The key (first type parameter)
         // is of type string, and the type to be contained in the
         // dictionary is Example.
        Type[] typeArgs = { typeof( string),  typeof(Example)};

         // Construct the type Dictionary<String, Example>.
        Type constructed = d1.MakeGenericType(typeArgs);

        DisplayGenericType(constructed);

         object o = Activator.CreateInstance(constructed);

        Console.WriteLine( "/r/nCompare types obtained by different methods:");
        Console.WriteLine( "   Are the constructed types equal? {0}",
            (d2.GetType()==constructed));
        Console.WriteLine( "   Are the generic definitions equal? {0}",
            (d1==constructed.GetGenericTypeDefinition()));

         // Demonstrate the DisplayGenericType and 
         // DisplayGenericParameter methods with the Test class 
         // defined above. This shows base, interface, and special
         // constraints.
        DisplayGenericType( typeof(Test<>));
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值