【问题标题】:How do I create and use a .NET metadata-only 'Reference Assembly'?如何创建和使用仅限 .NET 元数据的“参考程序集”?
【发布时间】:2011-09-26 12:22:19
【问题描述】:

从 3.0 版开始,.NET 在 C:\Program Files\Reference Assemblies\Microsoft.... 下安装了一堆不同的“参考程序集”,以支持不同的配置文件(例如 .NET 3.5 客户端配置文件、Silverlight 配置文件)。其中每一个都是正确的 .NET 程序集,仅包含元数据 - 没有 IL 代码 - 每个程序集都标有 ReferenceAssemblyAttribute。元数据仅限于适用配置文件下可用的那些类型和成员 - 这就是智能感知显示一组受限类型和成员的方式。运行时不使用引用程序集。

我从this blog post那里学到了一点。

我想为我的库创建和使用这样的参考程序集。

  1. 如何创建仅元数据程序集 - 是否有一些编译器标志或 ildasm 后处理器?
  2. 是否有属性可以控制将哪些类型导出到不同的“配置文件”?
  3. 如何在运行时解析参考程序集 - 如果我的应用程序目录中存在参考程序集而不是“真实”程序集,而不是 GAC 中,那么探测将继续并且我的 AssemblyResolve 事件触发,以便我可以在运行时提供实际的程序集吗?

任何想法或指示我可以在哪里了解更多关于这方面的信息将不胜感激。

更新: 环顾四周,我发现 .NET 3.0 的“参考程序集”似乎确实有一些代码,而 Reference Assembly attribute 仅在 .NET 4.0 中添加。因此,新运行时的行为可能会有所改变。

为什么? 对于我的 Excel-DNA (http://exceldna.codeplex.com) 插件库,我通过将引用的程序集作为资源打包到 .xll 文件中来创建单文件 .xll 插件。打包的程序集包括用户的加载项代码,以及 Excel-DNA 托管库(可能被用户程序集引用)。

这听起来相当复杂,但在大多数情况下运行得非常好 - 加载项是一个小文件,因此没有安装分发问题。由于版本不同,我遇到了(并非意外)问题 - 如果有旧版本的 Excel-DNA 托管库作为文件,运行时将加载它而不是打包的(我从来没有机会干扰加载中)。

我希望为我的 Excel-DNA 托管部件制作一个参考程序集,用户可以在编译他们的加载项时指向它。但是如果他们在运行时错误地拥有了这个程序集的版本,那么运行时应该无法加载它,并让我有机会从资源中加载真正的程序集。

【问题讨论】:

    标签: c# .net assemblies


    【解决方案1】:

    要创建参考程序集,您可以将此行添加到您的 AssemblyInfo.cs 文件中:

    [assembly: ReferenceAssembly]
    

    要加载其他人,您可以照常从您的 VisualStudio 项目引用中引用它们,或者在运行时动态地使用:

    Assembly.ReflectionOnlyLoad()

    Assembly.ReflectionOnlyLoadFrom()


    如果您使用 VisualStudio 添加了对元数据/引用程序集的引用,则智能感知和构建项目将正常工作,但是如果您尝试针对其中执行应用程序,则会收到错误消息:

    System.BadImageFormatException:无法加载要执行的参考程序集。

    因此期望在运行时您将替换为具有相同元数据签名的真实程序集。

    如果您已经使用Assembly.ReflectionOnlyLoad() 动态加载了程序集,那么您只能对其执行所有反射操作(读取类型、方法、属性、属性等,但不能动态调用它们中的任何一个)。


    我很好奇您创建仅元数据程序集的用例是什么。我以前从来没有这样做过,很想知道你是否发现了它们的一些有趣用途......

    【讨论】:

    • 组成一个人为的例子:您可以使用例如创建一个 .NET 程序集的本机映像。单声道 mkbundle.exe。现在您可能仍然希望允许插件 dll 访问原始程序集的公共接口。我相信你可以让它这样工作。如果有的话,它会导致 really 混淆和 large 程序集:)
    • 添加 ReferenceAssembly 属性不会将输出更改为仅元数据的程序集,如 .NET 4 引用程序集。我试图找出这些是如何构建的。我必须尝试,但是在处理了 BadImageFormatException 之后,您认为程序集解析会调用我的 AssemblyResolve 处理程序吗? (我将在问题中添加我的用例的详细信息。)
    • 我添加了一些关于我为什么感兴趣的信息。 @sehe 离目标不远!这些打包的程序集实际上很小,因为我在打包之前对其进行了压缩,而 CLI 程序集的压缩效果非常好。结果仅在“晦涩”的意义上被混淆 - .NET 程序集不在您的面前,因此您必须在将它们指向 ILSpy 之前做一些工作。但这种混淆器将是另一个很好的用例。
    【解决方案2】:

    如果您仍然对这种可能性感兴趣,我已经基于 Mono.Cecil 制作了 il-repack 项目的一个分支,它接受“/meta”命令行参数来为公共和受保护的仅生成元数据程序集类型。

    https://github.com/KarimLUCCIN/il-repack/tree/xna

    (我在完整的 XNA 框架及其工作 afaik 上进行了尝试...)

    【讨论】:

    • 谢谢(也在这里发帖)!仍然有兴趣 - 有机会我会看看。
    【解决方案3】:

    是的,这是 .NET 4.0 的新功能。我很确定这样做是为了避免 .NET 2.0 服务包中令人讨厌的版本控制问题。最好的例子是在 SP2 中添加和记录的 WaitHandle.WaitOne(int) 重载。一种流行的重载,因为它避免了在 WaitOne(int, bool) 重载中猜测 *exitContext" 的正确值。问题是,当程序在早于 SP2 的 2.0 版本上运行时,程序会爆炸。不开心诊断也是。隔离参考程序集可确保不会再次发生这种情况。

    认为这些引用程序集是通过从已编译程序集的副本开始创建的(就像在以前的版本中所做的那样)并通过从程序集中剥离 IL 的工具运行它们。然而,该工具对我们不可用,bin/netfx 4.0 tools Windows 7.1 SDK 子目录中没有任何东西可以做到这一点。不完全是一个经常使用的工具,所以它可能不是生产质量:)

    【讨论】:

    • 汉斯,我相信这个工具的使用频率实际上比你想象的要多。仅元数据程序集也用于引导 Core .Net Framework 程序集,如this answer 中关于它们如何编译 .Net Framework 程序集的问题中所述。当然,还可以通过特殊工具对这些程序集进行其他更改,例如将引用 m_value 成员的原始类型替换为对 this 的引用。
    • 感谢 Kevin 提供指向另一个问题的指针。因此,这些参考程序集是“脱水”的仅元数据程序集。
    • @Kevin - 我不这么认为。在这种情况下必须剥离 IL 是没有意义的。它在构建时不会被使用。
    • 也许这不是真正的原因,但在某些情况下构建 FCL 时肯定会使用剥离的程序集。在接下来的几天里,我会以对这个问题的答案的形式对此(以及微软内部使用的工具)有更多的看法。
    • 谢谢凯文!我期待您的见解。
    【解决方案4】:

    您可能对 Cecil 库(来自 Mono)很幸运;我认为该实现允许 ILMerge 功能,它也可以只编写元数据程序集。

    我已经扫描了代码库(文档很少),但还没有发现任何明显的线索......

    YYMV

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-13
      • 1970-01-01
      相关资源
      最近更新 更多