2010-09-21 59 views
17

我在我的(巨大的).NET 4项目中遇到了一个奇怪的行为。在代码中的某些时候,我指的是一个完全合格的类型,说:如果typeof(Xyz)存在,为什么System.Type.GetType(“Xyz”)返回null?

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; 
} 

回答

26

如果你只是给出一个类名(确实需要在命名空间方面完全合格),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的,版本= 4.0.0.0,文化=中立,
公钥= b77a5c561934e089
System.Windows.Forms.Form中

需要注意的是,如果你(在这种情况下,像Form)使用强命名程序集,你必须包括所有组件信息 - 版本,公钥令牌等

如果您使用非强命名程序集,它更容易 - 是这样的:

Foo.Bar.Baz, MyCompany.MyAssembly 

一个名为Baz型命名空间Foo.Bar,装配MyCompany.MyAssembly。注意最后没有“.dll” - 这是文件名的一部分,但不是程序集名称。

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

+0

非常感谢您的回复。事实上,我到目前为止解决的所有其他类型都位于相同的程序集或mscorlib中,所以我之前没有发现该错误。 – 2010-09-21 09:24:11

+0

即使程序集具有强名称,也可以使用部分程序集信息提供'System.Type.GetType'。我已经检查过'System.Type.GetType(“Foo.Bar.Baz,MyCompany.MyAssembly”),即使“MyCompany.Assembly”具有强名称,它也能正常工作。 – 2010-09-21 09:26:00

+0

以供将来参考,如果您想在代码高亮中使用反引号(并且您可能会;),请使用双反引号来开始和关闭引用:)。参见[这里](http://meta.stackexchange.com/q/82718/237379)。 – Noctis 2014-07-27 02:30:37

4

据我知道的GetType名为Foo.Bar.dll,我组装查找“XYZ”假设它不存在。

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

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

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

4

MSDN documentation(我的重点):

如果typeName的包括命名空间,但不集名称,这种方法搜索只有调用对象的组装的Mscorlib.dll,按照这个顺序。如果typeName用部分或完整程序集名称完全限定,则此方法在指定程序集中搜索。如果装配体名称很强,则需要一个完整的装配体名称。

1

我只是偶然发现了一个类似的问题,要离开这个位置

的首先你可以将字符串

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

然而,对于组件这只能如果没有一个强有力的指定的AssemblyName名称。解释已经在西蒙斯回答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(...)具有acceps组装一个FUNC过载,并键入解决这整齐。不推荐使用Assembly.LoadWithPartialName,但如果在将来删除它,我可以考虑替换(迭代当前AppDomain中的所有程序集并比较部分名称)。

相关问题