为什么GetType()在通过方法组委托调用时无法找到类型?

Ten*_*ner 144 c# reflection

我们有一个非常简单的程序来调用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));
    }
}
Run Code Online (Sandbox Code Playgroud)

运行:

Full name: GetTypeBeingWeird.TestClass
Method group: ''
Closure: 'GetTypeBeingWeird.TestClass'
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 165

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

首先,Type.GetType文档包括:

如果typeName包含命名空间但不包含程序集名称,则此方法仅按顺序搜索调用对象的程序集和Mscorlib.dll.

在你的第一次调用中,你传递的是一个调用的委托Type.GetType......但是你的程序集并没有特别调用它.它直接SelectLINQ中的方法调用...如果你从内部Type.GetType查看堆栈跟踪Select,我相信你会看到直接调用者.

在你的第二次调用中,你传入一个调用的闭包Type.GetType,并且该调用在你的程序集中.

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

var fullName = typeof(Enumerable).FullName;
Run Code Online (Sandbox Code Playgroud)

然后结果是相反的方式:

Full name: System.Linq.Enumerable
Method group: 'System.Linq.Enumerable'
Closure: ''
Run Code Online (Sandbox Code Playgroud)

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

Full name: System.String
Method group: 'System.String'
Closure: 'System.String'
Run Code Online (Sandbox Code Playgroud)

在寻找你​​的类时,仍然使用方法组来解决这种奇怪的方法只是提供程序集限定的名称:

var fullName = typeof(TestClass).AssemblyQualifiedName;
Run Code Online (Sandbox Code Playgroud)

  • 哇,使用调用程序集作为隐藏输入是可怕的.但有趣的是bug. (16认同)
  • 使用调用程序集而不是输入或执行默认值可能(并且我确定确实)是一个深思熟虑的决定.我能想到的一个原因是,如果入口/执行程序集声明了与mscorelib匹配的相同名称空间和类型名称,则在mscorelib调用Type.GetType()时避免类型欺骗.一名男子的"视频"是另一名男子没有通过标准图书馆劫持将他的屁股交还给他. (5认同)
  • API不应将*a​​ny*程序集作为隐藏输入.它应该由调用者指定.使用入口组件几乎一样糟糕.没有程序集名称的类型名称很简单.没有好的消歧策略可行. (5认同)