如果 typeof(Xyz) 存在,为啥 System.Type.GetType("Xyz") 返回 null?

Posted

技术标签:

【中文标题】如果 typeof(Xyz) 存在,为啥 System.Type.GetType("Xyz") 返回 null?【英文标题】:Why would System.Type.GetType("Xyz") return null if typeof(Xyz) exists?如果 typeof(Xyz) 存在,为什么 System.Type.GetType("Xyz") 返回 null? 【发布时间】:2011-04-15 01:34:34 【问题描述】:

我在我的(巨大的).NET 4 项目中遇到了一个奇怪的行为。在代码中的某个位置,我指的是完全限定类型,比如:

System.Type type = typeof (Foo.Bar.Xyz);

稍后,我会这样做:

System.Type type = System.Type.GetType ("Foo.Bar.Xyz");

然后我回复null。我无法理解为什么会发生这种情况,因为我的类型名称是正确的,并且我已经检查了其他类型并且它们得到了正确解决。此外,以下 LINQ 查询会找到类型:

var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
            from assemblyType in assembly.GetTypes ()
            where assemblyType.FullName == typeName
            select assemblyType;

System.Type type = types.FirstOrDefault ();

System.Type.GetType 可能失败的原因有哪些?

我终于不得不求助于这段代码而不是GetType

System.Type MyGetType(string typeName)

    System.Type type = System.Type.GetType (typeName);

    if (type == null)
    
        var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies ()
                    from assemblyType in assembly.GetTypes ()
                    where assemblyType.FullName == typeName
                    select assemblyType;

        type = types.FirstOrDefault ();
    

    return type;

【问题讨论】:

【参考方案1】:

如果您只给出一个类名(当然,确实需要完全限定命名空间)Type.GetType(string) 将只查看当前正在执行的程序集和 mscorlib。如果要从任何其他程序集中获取类型,则需要指定包含程序集信息的绝对全名。正如 François 所说,Type.AssemblyQualifiedName 是一种很好的看待这一点的方式。这是一个例子:

using System;
using System.Windows.Forms;

class Test

    static void Main()
    
        string name = typeof(Form).AssemblyQualifiedName;
        Console.WriteLine(name);

        Type type = Type.GetType(name);
        Console.WriteLine(type);
    

输出:

System.Windows.Forms.Form,System.Windows.Forms,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089 System.Windows.Forms.Form

请注意,如果您使用的是强命名程序集(如本例中的 Form),您必须包含所有程序集信息 - 版本控制、公钥令牌等。

如果您使用的是非强命名程序集,则更容易 - 类似于:

Foo.Bar.Baz, MyCompany.MyAssembly

对于命名空间 Foo.Bar 中名为 Baz 的类型,在程序集 MyCompany.MyAssembly 中。请注意末尾没有“.dll” - 这是文件名的一部分,但不是程序集名称。

您还应该了解 C# 名称和 CLR 名称在嵌套类和泛型等方面的区别。例如,typeof(List<>.Enumerator) 的名称为 System.Collections.Generic.List`1+Enumerator[T]。泛型方面很难解决,但嵌套类型位很容易——它只是用“+”而不是“.”来表示。你会在 C# 中使用。

【讨论】:

非常感谢您的回复。事实上,到目前为止我正在解析的所有其他类型要么位于同一个程序集中,要么位于 mscorlib 中,所以我之前没有发现这个错误。 System.Type.GetType 提供部分程序集信息也有效,即使程序集具有强名称。我检查了System.Type.GetType("Foo.Bar.Baz, MyCompany.MyAssembly"),即使MyCompany.Assembly 有一个强名称,它也可以工作。 为了将来参考,如果你想在代码高亮中使用反引号(你可能会;),使用双反引号开始和关闭引号:)。见here。 @Noctis:谢谢 - 会努力记住 :)【参考方案2】:

据我所知,GetType 在名为 Foo.Bar.dll 的程序集中查找“Xyz”,我假设它不存在。

GetType 依赖于您在程序集中将确切路径传递给 Xyz。 程序集和命名空间不必相关。

试试System.Type type = System.Type.GetType(typeof(Foo.Bar.Xyz).AssemblyQualifiedName) 看看是否可行。

您在 LINQ 示例中找到它的原因是您正在使用 GetAssemblies,它获取已加载到当前执行上下文中的程序集,因此具有查找程序集中所有类型所需的详细信息。

【讨论】:

【参考方案3】:

来自MSDN documentation(我的重点):

如果 typeName 包含命名空间但不包含程序集名称,则此方法按此顺序仅搜索调用对象的程序集和 Mscorlib.dll。如果 typeName 是完全限定的部分或完整程序集名称,则此方法在指定的程序集中进行搜索。如果程序集具有强名称,则需要完整的程序集名称。

【讨论】:

【参考方案4】:

我只是偶然发现了一个类似的问题,想把它留在这里

首先你可以在字符串中指定 AssemblyName

var type = System.Type.GetType("Foo.Bar.Xyz, Assembly.Name");

但这仅适用于没有强名称的程序集。解释已经在 Simons answer If the assembly has a strong name, a complete assembly name is required.

我的问题是我必须在运行时从字符串中解析 System.Dictionary<?,?>。对于Dictionary<int, string>,这可能很容易,但Dictionary<int, Image> 呢?

这会导致

var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]]";

但我不想写强名称。特别是因为我不想包含这些版本,因为我打算用我的代码针对多个框架。

这是我的解决方案

    privat statice void Main()
    
        var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing]]";
        var type = Type.GetType(typeName, ResolveAssembly, ResolveType);
    

    private static Assembly ResolveAssembly(AssemblyName assemblyName)
    
        if (assemblyName.Name.Equals(assemblyName.FullName))
            return Assembly.LoadWithPartialName(assemblyName.Name);
        return Assembly.Load(assemblyName);
    

    private static Type ResolveType(Assembly assembly, string typeName, bool ignoreCase)
    
        return assembly != null
            ? assembly.GetType(typeName, false, ignoreCase)
            : Type.GetType(typeName, false, ignoreCase);
    

Type.GetType(...) 有一个重载,它接受一个用于组装和类型解析的函数。 Assembly.LoadWithPartialName 已弃用,但如果将来删除它,我可以考虑替换(迭代当前 AppDomain 中的所有程序集并比较部分名称)。

【讨论】:

以上是关于如果 typeof(Xyz) 存在,为啥 System.Type.GetType("Xyz") 返回 null?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 3.times 需要一个 .each 如果作为参数传递,但直接使用时不需要,如“3.times do xyz end”

为啥 typeof 有时只抛出 ReferenceError?

JavaScript为啥(typeof Object)返回的是function

为啥要使用 toString() 对可以使用 typeof 进行检查的参数进行类型检查?

为啥带有对象的 typeof 数组返回“object”而不是“array”? [复制]

“typeof firebase”类型不存在属性“default”。错误