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

C# 为什么通过方法组委托调用时GetType()找不到类型?,c#,reflection,C#,Reflection,我们有一个调用Type.GetType静态方法的非常简单的程序。这两个示例都应该返回一个有效的类型实例。实际上只有第二个是。GetType使用的堆栈爬网看起来有些奇怪,但这里的问题到底是什么?是bug还是一些模糊的特性 public class TestClass { } class Program { static void Main(string[] args) { var fullName = typeof(TestClass).FullName;

我们有一个调用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'

这真的很有趣。它是Type.GetTypestring在调用程序集方面的行为和方法组转换的工作方式的混合体

首先,文件包括:

如果typeName包含名称空间,但不包含程序集名称,则此方法仅按该顺序搜索调用对象的程序集和Mscorlib.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: ''
如果您在mscorlib中指定了某些内容,例如typeofstring.FullName,则这两种方法都有效:

Full name: System.String
Method group: 'System.String'
Closure: 'System.String'
在仍然使用方法组的情况下查找类时,避免这种奇怪现象的方法只是提供程序集限定名:

var fullName = typeof(TestClass).AssemblyQualifiedName;

哇,使用调用程序集作为隐藏输入是可怕的。不过,有趣的bug。使用调用程序集而不是默认的条目或执行可能是,我确信这确实是一个深思熟虑的决定。我能想到的一个原因是,如果条目/执行程序集声明了与mscorelib匹配的相同命名空间和类型名,则在mscorelib调用type.GetType时避免类型欺骗。一个人的hideo是另一个人没有通过std库劫持将屁股交给他。API不应该将任何程序集作为隐藏输入。它应该由调用方指定。使用入口程序集几乎同样糟糕。没有程序集名称的类型名是不明确的。没有好的消除歧义的策略是可能的。@Jon你真的是这个意思吗?这就是为什么它会在第一个案例中找到类型,但不是第二个,或者你的意思是:第二个案例,但不是第一个,我是confused@EʜsᴀɴSᴀᴊᴊᴀᴅ: 对于这个特定的调用,如果您只指定一个命名空间限定的类型名,那么选择yes。对于大多数不关心调用程序集的方法,或者如果您指定的是程序集限定名,则可以。我是否应该关闭旧的方法?不确定,欢迎对此发表意见。。。