当通过方法组委托调用时,为什么 GetType()不能找到类型?

我们有一个调用 Type.GetType静态方法的非常简单的程序。这两个示例都应该返回一个有效的类型实例。只有第二个是真的。看起来 GetType使用的堆栈抓取发生了一些奇怪的事情,但是这里的问题究竟是什么呢?是 bug 还是什么模糊的特性?

public class TestClass { }


class Program
{
static void Main(string[] args)
{
var fullName = typeof(TestClass).FullName;
Console.WriteLine("Full name: {0}", fullName);


new[] { fullName }.Select(Type.GetType).ToList().ForEach(t => Console.WriteLine("Method group: '{0}'", t));
new[] { fullName }.Select(t => Type.GetType(t)).ToList().ForEach(t => Console.WriteLine("Closure: '{0}'", t));
}
}

跑步:

Full name: GetTypeBeingWeird.TestClass
Method group: ''
Closure: 'GetTypeBeingWeird.TestClass'
7296 次浏览

这真的很有趣。它混合了 Type.GetType(string)在调用程序集方面的行为以及方法组转换的工作方式。

首先,Type.GetType文档包括以下内容:

如果 类型名称包含命名空间而不包含程序集名称,则此方法将按照该顺序仅搜索调用对象的程序集和 Mscolib.dll。

在您的第一次调用中,您传入了一个调用 Type.GetType的委托... ... 但它并不是从您的程序集中特别调用的。它实际上是从 LINQ 中的 Select方法调用的 直接... ... 如果您从 Type.GetType中查看堆栈跟踪,您将看到 Select作为直接调用方,我相信。

在第二个调用中,传入了一个调用 Type.GetType的闭包,并且该调用位于程序集中。

这就是为什么它在第二种情况下找到类型,而不是在第一种情况下。通过指定 LINQ 程序集中的类型进一步验证:

var fullName = typeof(Enumerable).FullName;

结果恰恰相反:

Full name: System.Linq.Enumerable
Method group: 'System.Linq.Enumerable'
Closure: ''

如果你在 mscolib 中指定一些内容(例如 typeof(string).FullName) ,那么这两种方法都有效:

Full name: System.String
Method group: 'System.String'
Closure: 'System.String'

在查找仍然使用方法组的类时,避免这种奇怪现象的方法只是提供程序集限定的名称:

var fullName = typeof(TestClass).AssemblyQualifiedName;