我在我的(巨大的).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;
}
答案 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)
我偶然发现了一个类似的问题,并希望将其留在这里
首先,您可以在字符串
中指定AssemblyNamevar 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中的所有程序集并比较部分名称)。