【问题标题】:How can I get a type from an assembly that is loaded from within another folder?如何从另一个文件夹中加载的程序集中获取类型?
【发布时间】:2011-11-04 16:38:28
【问题描述】:

我使用以下代码:

Assembly.LoadFile("the assembly in another folder");
var type = Type.GetType("the full name of the type");

即使程序集在这行代码之前已经加载,它总是在 type 中返回 null。

PS:我确实传入了程序集限定名,包括命名空间、类型名、程序集名称、版本和公共令牌。

【问题讨论】:

  • assembly 是否与汇编语言有某种关系?
  • @KirilKirov:不。这是 .Net 中的一种类型。
  • @Austin - 啊,谢谢 :) 我被标签误导了。

标签: c# .net reflection


【解决方案1】:

Type.GetType 仅搜索调用程序集中的类型和 mscorlib.dll 中的类型,除非您传递类型的程序集限定名。 See here.

编辑

Type.GetType 似乎只能从 Load 上下文中的程序集中检索 Type 实例。使用LoadFile 加载的程序集在no context 中,使用LoadFrom 加载的程序集在Load From 上下文中;这些上下文都不允许您使用Type.GetType,因此解析将失败。 This article 表明,当 Assembly 所在的目录被添加为探测 privatePath 时,可以检索到 Type 信息,因为它会在 Load 上下文中结束,但在其他上下文中会失败。

【讨论】:

  • 我确实传入了程序集限定名,包括命名空间、类型名称、程序集名称和版本、公共令牌。
  • @CuiPengFei 只是为了消除显而易见的问题,您确定程序集限定名称与静态引用程序集并调用typeof(TypeName).AssemblyQualifiedName 时获得的区分大小写的值完全匹配吗?
  • @CuiPengFei:我试过使用Type.GetType,但没有成功,所以我赞同@EvanWilliams 的回答是最好的解决方案。
  • 由于某种原因,此回复中引用的文章不再可用 - 有人知道如何再次获得它吗?
【解决方案2】:

执行此操作的“正确”(MS 推荐)方法,当您必须对不在加载上下文但在加载源或无上下文上下文中的程序集中的类型使用 Type.GetType(string) 时,绑定到Appdomain.AssemblyResolve 事件。下面的代码比较高效:

// this resolver works as long as the assembly is already loaded
// with LoadFile/LoadFrom or Load(string) / Load(byte[])
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
    var asm = (from a in AppDomain.CurrentDomain.GetAssemblies()
              where a.GetName().FullName == args.Name
              select a).FirstOrDefault();

    if(asm == null)
         throw FileNotFoundException(args.Name);     // this becomes inner exc

    return asm;
}

// place this somewhere in the beginning of your app:
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;

创建 AssemblyLoad/Resolve 事件的组合以保留已加载程序集的字典似乎更有效(使用程序集名称作为键)。

关于 Assembly.LoadFile
使用这种方法有一些严重的缺点。 According to MSDN:

LoadFile 不会将文件加载到 LoadFrom 上下文中,也不会像 LoadFrom 方法那样使用加载路径解析依赖关系。

因此,如果可能,请不要使用 LoadFile。生成的程序集在无上下文上下文中加载,这比从上下文中加载的缺点更多。相反,使用Assembly.LoadFrom 并且依赖项将自动从加载路径加载。

【讨论】:

    【解决方案3】:

    最简单的方法是简单地将 Assembly.LoadFile 的返回值捕获在一个变量中,然后像这样调用 GetType:

    Assembly assem = Assembly.LoadFile("assemblyLocation");
    assem.GetType("typeName");
    

    如果您想经常从中提取类型,或者执行其他人的建议并创建一个更通用的方法来循环所有加载的程序集,您可能需要考虑保留对此程序集的引用。

    【讨论】:

      【解决方案4】:

      你可以试试这个......

      Assembly.GetAssembly 假定您拥有该类型的实例,而 Type.GetType 假定您拥有包含程序集名称的完全限定类型名称。

      你可以给出程序集所在的路径.....

      如果你只有基本类型名称,你需要做更多这样的事情:

      public static String GetAssemblyNameContainingType(String typeName) 
      {
          foreach (Assembly currentassembly in AppDomain.CurrentDomain.GetAssemblies()) 
          {
              Type t = currentassembly.GetType(typeName, false, true);
              if (t != null) {return currentassembly.FullName;}
          }
      
          return "not found";
      }
      

      这也假设您的类型是在根中声明的。您需要在名称中提供命名空间或封闭类型,或者以相同的方式进行迭代。

      【讨论】:

      • 加载程序集时要小心,因为一旦将它们加载到 AppDomain 中,就无法再卸载它们。如果您有很多程序集要加载,请考虑创建单独的 AppDomain 来完成处理程序集并返回结果的工作,然后可以将其释放。
      • 我不推荐这个。相反,绑定到AppDomain.AssemblyResolve 事件。这样,您只返回所需的程序集,在上面的代码中,您搜索每个加载的程序集,然后开始加载当前不需要的程序集
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      相关资源
      最近更新 更多