【问题标题】: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;
}

【问题讨论】:

    标签: assemblies clr types gettype


    【解决方案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 中的所有程序集并比较部分名称)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-22
          相关资源
          最近更新 更多