【问题标题】:How Type.GetType works when given partially qualified type name?给定部分限定的类型名称时,Type.GetType 如何工作?
【发布时间】:2011-01-22 23:37:13
【问题描述】:

我在很多地方都遇到过 FullTypeName, AssemblyName 形式的部分限定类型名称,即像 Type.AssemblyQualifiedName 只是没有版本、文化和 publicKeyToken 限定符。

我的问题是如何以最少的努力将其转换为相应的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().FullName 等。阿尔?如果您在运行时拥有该类型,则可以使用 .GetType().FullName 等。人。还是我错过了具体要求?我知道您只想指定一个部分名称,但对于加载器而言,这实际上比对于类型系统而言更多。 FQN 用于在发生名称冲突的罕见情况下消除引用问题的歧义,这在用户程序集中比在 BCL 程序集中更常见。
  • 我非常清楚 typeof() 或 Type.FullName。对象的类型是从配置文件中读取的,这就是我使用 Type.GetType 的原因。这就是为什么我对了解部分限定类型名称的工作方式如此感兴趣的原因。

标签: .net types


【解决方案1】:

没错,Type.GetType(string) 确实需要 AssemblyQualifiedName。这可以有多种形式:

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

以下也是有效的 AssemblyQualifiedNames:

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

对于未签名的程序集,FullyQualifiedAssemblyName 的最低要求是:

MyNS.MyType, MyAssembly

不需要其他人提供的代码 sn-ps 中的所有“挥手”。确保您的类型名称设置正确,并且您可以高度灵活地访问您的类型(并动态加载程序集)。我经常这样做。

在 OP 的示例中使用:

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

失败的原因是缺少 PublicKeyToken。 .Net FW 程序集均已签名,因此需要 PublicKeyToken 来解析程序集名称。以下将起作用:

Type.GetType("System.Net.Sockets.SocketException, System, PublicKeyToken=b77a5c561934e089")

【讨论】:

  • 坦率地说,这应该是 MSDN 解释它的方式。很有道理,并解释了为什么这种方法在很多情况下表现得如此不一致。
【解决方案2】:

刚刚经历了一些遗留代码的类似问题,我认为已接受答案中的第一条语句是不正确的。程序集是否已经加载并不重要。

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

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

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

【讨论】:

    【解决方案3】:

    如果程序集已经加载到当前域中,那么下面的代码通常可以工作:

    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");
    

    【讨论】:

    • 非常感谢您的回答!这正是我想要的——比“接受”的答案要好得多。
    【解决方案4】:

    使用缩写形式的代码是:

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

    但 LoadWithPartialName 已被弃用,所以我想你应该坚持使用长格式。

    【讨论】:

      【解决方案5】:

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

      回答你的问题:第二个版本总是有效的,坚持下去,你有一个担心的方法。

      【讨论】:

      • 我认为程序集是否已经加载并不重要 - 短版本不起作用。如果类型在当前执行的程序集中或在 mscorlib 中,则命名空间限定名称将起作用。下面有更全面的解释。
      猜你喜欢
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 2012-07-02
      • 2010-10-01
      • 2015-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多