当给出部分限定类型名称时,Type.GetType如何工作?

21

我经常遇到形如FullTypeName, AssemblyName的部分限定类型名称,在许多地方都会遇到,例如Type.AssemblyQualifiedName,只是没有版本、区域性和公钥令牌限定符。

我的问题是如何以最小的努力将其转换为相应的Type? 我认为Type.GetType可以完成这项工作,但不幸的是它并不行。 例如,以下代码返回null

Type.GetType("System.Net.Sockets.SocketException, System");

当然,如果我指定完整的限定名称,它就可以正常工作:

Type.GetType("System.Net.Sockets.SocketException, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

非常感谢。


你在编译时有类型吗?如果有,为什么不使用typeof(<type>).FullName等?如果你在运行时才有类型,那么你可以使用<object>.GetType().FullName等。或者我是否误解了具体请求?我知道你只想指定部分名称,但那真的更适用于加载器而不是类型系统。FQN用于消除参考问题的歧义,这种情况很少发生,真实情况是在用户程序集中经常发生而不是在BCL程序集中。 - GrayWizardx
1
我非常清楚typeof()或Type.FullName。对象的类型是从配置文件中读取的,这就是为什么我使用Type.GetType。这也是我非常有兴趣了解部分限定类型名称如何工作的原因。 - mark
5个回答

32
如果程序集已经在当前域中加载,则下面的代码通常可以工作:
public static Type GetTypeEx(string fullTypeName)
{
    return Type.GetType(fullTypeName) ??
           AppDomain.CurrentDomain.GetAssemblies()
                    .Select(a => a.GetType(fullTypeName))
                    .FirstOrDefault(t => t != null);
}

您可以这样使用它:
Type t = GetTypeEx("System.Net.Sockets.SocketException");

1
非常感谢您的回答!这正是我所寻找的 - 比“已接受”的答案好多了。 - Paul Hollingsworth

9

如果DLL不在应用程序域中加载(例如,您使用了它),则需要像这样使用完整路径,如果已经加载,则可以使用较短的版本找到它。

回答您的问题:第二个版本始终有效,请坚持使用它,这样您只需要担心一种方式。


1
我认为这并不重要,无论程序集是否已加载 - 简短的版本都不起作用。如果类型在当前执行的程序集或mscorlib中,则限定命名空间名称将起作用。下面有更详细的解释。 - lesscode

3

确实,Type.GetType(string)需要一个程序集限定名。这个限定名可以有多种形式:

MyNS.MyType, MyAssembly, Version=x.x.x.x, Culture=xxx, PublicKeyToken=XXXXXXXXXX

以下也是有效的程序集限定名称:
MyNS.MyType, MyAssembly, Version=x.x, Culture=xxx, PublicKeyToken=XXXXXXXXXX
MyNS.MyType, MyAssembly, Culture=xxx, PublicKeyToken=XXXXXXXXXX
MyNS.MyType, MyAssembly, PublicKeyToken=XXXXXXXXXX
MyNS.MyType, MyAssembly

对于已签名的程序集,FullyQualifiedAssemblyName 的最小要求是:
MyNS.MyType, MyAssembly, PublicKeyToken=XXXXXXXXXX

对于未签名的程序集,完全限定程序集名称所需的最少信息为:
MyNS.MyType, MyAssembly

不需要其他人提供的代码片段中所谓的“手舞足蹈”。确保您的类型名称正确设置,并且可以高度灵活地访问您的类型(以及动态加载程序集)。我经常这样做。
在原帖的示例中使用:
Type.GetType("System.Net.Sockets.SocketException, System")

失败的原因是缺少PublicKeyToken。.Net FW程序集都是签名的,因此需要PublicKeyToken来解析程序集名称。以下内容可以正常工作:
Type.GetType("System.Net.Sockets.SocketException, System, PublicKeyToken=b77a5c561934e089")

坦白地说,这应该是MSDN解释的方式。这很有道理,并且解释了为什么在许多情况下,这种方法的行为看起来如此不一致。 - tobriand

2

使用短格式的代码如下:

    Assembly a = Assembly.LoadWithPartialName(assemblyName);
    Type t = a.GetType(typeName);

但是LoadWithPartialName已经被弃用,所以我猜你应该坚持使用完整的形式。


2

我刚刚通过一些遗留代码遇到了类似的问题,我认为被接受的答案中的第一个语句是不正确的。这与程序集是否已加载无关。

根据文档,Type.GetType(string) 需要一个 AssemblyQualifiedName,除非所讨论的类型在当前执行的程序集或mscorlib中,此时只需要命名空间限定的类型名称。

请注意,AssemblyQualifiedName 包括类型的程序集的完整 DisplayName(带版本、区域性和公钥标记)。

除非您使用自定义的 AssemblyResolver 来拦截失败的类型加载(这实际上就是我的问题,掩盖了另一个问题),否则短名称版本将无法工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接