如果typeof(Xyz)存在,为什么System.Type.GetType(“Xyz”)会返回null?

时间:2010-09-21 07:38:18

标签: assemblies clr types gettype

我在我的(巨大的).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;
}

4 个答案:

答案 0 :(得分:27)

如果您只是给出一个类名(当然 需要在名称空间方面完全限定)Type.GetType(string)只会查看当前正在执行的程序集和mscorlib 。如果要从任何其他程序集中获取类型,则需要指定绝对全名,包括程序集信息。正如弗朗索瓦所说,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,Version = 4.0.0.0,Culture = neutral,
  公钥= b77a5c561934e089
  System.Windows.Forms.Form中

请注意,如果您使用强名称程序集(在本例中为Form),则必须包含 all 程序集信息 - 版本控制,公钥令牌等。

如果您使用的是非强名称的程序集,则更容易 - 例如:

Foo.Bar.Baz, MyCompany.MyAssembly

表示程序集Baz中名称空间Foo.Bar中名为MyCompany.MyAssembly的类型。注意最后没有“.dll” - 这是文件名的一部分,而不是程序集名称。

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

答案 1 :(得分:4)

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

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

尝试System.Type type = System.Type.GetType(typeof(Foo.Bar.Xyz).AssemblyQualifiedName),看看是否有效。

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

答案 2 :(得分:4)

MSDN documentation(我的重点):

  

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

答案 3 :(得分:1)

我偶然发现了一个类似的问题,并希望将其留在这里

首先,您可以在字符串

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

但是,这仅适用于没有强名称的程序集。解释已经在Simons回答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(...)有一个重载函数,用于汇编func以进行汇编和类型解析。 Assembly.LoadWithPartialName已弃用,但如果将来删除,我可以考虑替换(迭代当前AppDomain中的所有程序集并比较部分名称)。