在C#中,什么情况下Type.FullName返回null?

26
Type.FullName的MSDN文档指出该属性返回以下内容:
如果当前实例表示泛型类型参数、数组类型、基于类型参数的指针类型或byref类型,或者是不是泛型类型定义但包含未解析类型参数的泛型类型,则返回null
我数了一下,这里有五种情况,每一种都更加不清晰。以下是我构造每种情况的示例的尝试。
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication {
  public static class Program {

    public static void Main(string[] args) {
      GenericTypeParameter();
      ArrayType();
      PointerType();
      ByRefTypeBasedOnTypeParameter();
      NongenericTypeDefinitionWithUnresolvedTypeParameters();
      Console.ReadKey();
    }

    public static void GenericTypeParameter() {
      var type = typeof(IEnumerable<>)
        .GetGenericArguments()
        .First();
      PrintFullName("Generic type parameter", type);
    }

    public static void ArrayType() {
      var type = typeof(object[]);
      PrintFullName("Array type", type);
    }

    public static void PointerType() {
      var type = typeof(int*);
      PrintFullName("Pointer type", type);
    }

    public static void ByRefTypeBasedOnTypeParameter() {
      var type = null;
      PrintFullName("ByRef type based on type parameter", type);
    }

    private static void NongenericTypeDefinitionWithUnresolvedTypeParameters() {
      var type = null;
      PrintFullName("Nongeneric type definition with unresolved type parameters", type);
    }

    public static void PrintFullName(string name, Type type) {
      Console.WriteLine(name + ":");
      Console.WriteLine("--Name: " + type.Name);
      Console.WriteLine("--FullName: " + (type.FullName ?? "null"));
      Console.WriteLine();
    }
  }
}

这是输出结果。
Generic type parameter:
--Name: T
--FullName: null

Array type:
--Name: Object[]
--FullName: System.Object[]

Pointer type:
--Name: Int32*
--FullName: System.Int32*

ByRef type based on type parameter:
--Name: Program
--FullName: ConsoleApplication.Program

Nongeneric type definition with unresolved type parameters:
--Name: Program
--FullName: ConsoleApplication.Program

我在五次尝试中只成功了一次,有两次是“空白”的。

问题

有人能够修改我的代码并举出 Type.FullName 可能为空的每种情况的简单例子吗?

2个回答

14
所以我立刻注意到MSDN引用在其情形列表中两次包含“或”一词,但是我花费了太长时间才意识到其中的原因。实际上,有三种主要情况,其中有其中一种分为三个进一步的情况。使用更清晰的标点符号,这些情况是:
  1. 通用类型参数;
  2. 基于类型参数的数组类型、指针类型或通过引用传递的类型; 或者
  3. 不是通用类型定义但包含未解决类型参数的通用类型。
我理解第一个情况,Rahul的答案指导我阅读此MSDN博客文章,该文章解释了并给出了最后一种情况的两个示例,现在我可以举出其余情况的示例。
using System;
using System.Linq;

namespace ConsoleApplication {

  public class GenericClass<T> {
    public void ArrayMethod(T[] parameter) { }
    public void ReferenceMethod(ref T parameter) { }
  }

  public class AnotherGenericClass<T> : GenericClass<T> { }

  public static class Program {

    public static void Main(string[] args) {
      GenericTypeParameter();
      ArrayTypeBasedOnTypeParameter();
      PointerTypeBasedOnTypeParameter();
      ByRefTypeBasedOnTypeParameter();
      NongenericTypeDefinitionWithUnresolvedTypeParameters();
      Console.ReadKey();
    }

    public static void GenericTypeParameter() {
      var type = typeof(GenericClass<>)
        .GetGenericArguments()
        .First();
      PrintFullName("Generic type parameter", type);
    }

    public static void ArrayTypeBasedOnTypeParameter() {
      var type = typeof(GenericClass<>)
        .GetMethod("ArrayMethod")
        .GetParameters()
        .First()
        .ParameterType;
      PrintFullName("Array type based on type parameter", type);
    }

    /*
     * Would like an actual example of a pointer to a generic type,
     * but this works for now.
     */
    public static void PointerTypeBasedOnTypeParameter() {
      var type = typeof(GenericClass<>)
        .GetGenericArguments()
        .First()
        .MakePointerType();
      PrintFullName("Pointer type based on type parameter", type);
    }

    public static void ByRefTypeBasedOnTypeParameter() {
      var type = typeof(GenericClass<>)
        .GetMethod("ReferenceMethod")
        .GetParameters()
        .First()
        .ParameterType;
      PrintFullName("ByRef type based on type parameter", type);
    }

    private static void NongenericTypeDefinitionWithUnresolvedTypeParameters() {
      var type = typeof(AnotherGenericClass<>).BaseType;
      PrintFullName("Nongeneric type definition with unresolved type parameters", type);
    }

    public static void PrintFullName(string name, Type type) {
      Console.WriteLine(name + ":");
      Console.WriteLine("--Name: " + type.Name);
      Console.WriteLine("--FullName: " + (type.FullName ?? "null"));
      Console.WriteLine();
    }
  }
}

/***Output***
Generic type parameter:
--Name: T
--FullName: null

Array type based on type parameter:
--Name: T[]
--FullName: null

Pointer type based on type parameter:
--Name: T*
--FullName: null

Byref type based on type parameter:
--Name: T&
--FullName: null

Nongeneric type definition with unresolved type parameters:
--Name: GenericClass`1
--FullName: null
***Output***/

1
你可以查看这个MSDN博客,它演示了Type.FullName何时返回null

For instance, suppose we have an assembly compiled with the following C# code:

class G<T> {
    public void M<S>() { } 
}

typeof(G<>).FullName is G`1, and we can round trip this type from Type.GetType(G`1). But we can build more complicated generic types, such as G<S> (type G<> bound with the generic parameter from the method M<>); in order to identify such type with a string, a lot of extra information is need.

Below are some examples where Type.FullName returns null.

class G<T> {
  public class C { }
  public void M(C arg) { }
}
class G2<T> : G<T> { }

string s1 = typeof(G<>).GetGenericArguments()[0].FullName; 
// T in G<T>: generic parameter
string s2 = typeof(G<>).GetMethod("M").GetParameters()[0].ParameterType.FullName; 
// check out the IL, it is G`1/C<!T> (not generic type definition) 
// Related topic, see this 
string s3 = typeof(G2<>).BaseType.FullName; 
// base type of G2<>, which is not generic type definition either
// it equals to typeof(G<>).MakeGenericType(typeof(G2<>).GetGenericArguments()[0])

很好。这篇博客文章是关于五种情况中的最后一种(参见他的最后两个例子),但也包括第一种情况的一个例子(参见他的第一个例子)以供比较。还有三种情况要讲解。 - Tyson Williams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接