如何创建和使用仅包含 .NET 元数据的“参考程序集”?
从版本 3.0 开始,.NET 在 C:\Program Files\Reference Assemblies\Microsoft... 下安装了一堆不同的“参考程序集”,以支持不同的配置文件(例如 .NET 3.5 客户端配置文件、Silverlight 配置文件)。其中每一个都是一个正确的 .NET 程序集,仅包含元数据(没有 IL 代码),并且每个程序集都用 ReferenceAssemblyAttribute
进行标记。元数据仅限于适用配置文件下可用的类型和成员 - 这就是智能感知显示一组受限类型和成员的方式。运行时不使用参考程序集。
我从这篇博文。
我想为我的库创建并使用这样的参考程序集。
- 如何创建仅元数据程序集 - 是否有一些编译器标志或 ildasm 后处理器?
- 是否有属性控制哪些类型导出到不同的“配置文件”?
- 运行时的引用程序集解析如何 - 如果我的应用程序目录中存在引用程序集而不是“真实”程序集,并且根本不在 GAC 中,那么探测会继续并且我的 AssemblyResolve 事件会触发,以便我可以提供运行时实际组装?
任何可以让我了解更多相关信息的想法或指示将不胜感激。
更新:环顾四周,我看到 .NET 3.0“参考程序集”似乎确实有一些代码,并且 参考程序集属性仅在.NET 4.0中添加。因此,随着新的运行时,行为可能会发生一些变化。
为什么? 对于我的 Excel-DNA ( http://exceldna.codeplex.com ) 加载项库,我通过将引用的程序集作为资源打包到 .xll 文件中来创建单文件 .xll 加载项。打包的程序集包括用户的加载项代码以及 Excel-DNA 托管库(可能由用户的程序集引用)。
这听起来相当复杂,但在大多数情况下都运行得非常好 - 加载项是一个小文件,因此没有安装分发问题。由于版本不同,我遇到了(并非意外的)问题 - 如果有旧版本的 Excel-DNA 托管库作为文件,运行时将加载该库而不是打包的库(我从来没有机会干扰加载中)。
我希望为我的 Excel-DNA 托管部件制作一个参考程序集,用户在编译其加载项时可以指向该部件。但是,如果他们在运行时错误地拥有该程序集的版本,则运行时应该无法加载它,并给我一个从资源加载真实程序集的机会。
Since version 3.0, .NET installs a bunch of different 'reference assemblies' under C:\Program Files\Reference Assemblies\Microsoft...., to support different profiles (say .NET 3.5 client profile, Silverlight profile). Each of these is a proper .NET assembly that contains only metadata - no IL code - and each assembly is marked with the ReferenceAssemblyAttribute
. The metadata is restricted to those types and member available under the applicable profile - that's how intellisense shows a restricted set of types and members. The reference assemblies are not used at runtime.
I learnt a bit about it from this blog post.
I'd like to create and use such a reference assembly for my library.
- How do I create a metadata-only assembly - is there some compiler flag or ildasm post-processor?
- Are there attributes that control which types are exported to different 'profiles'?
- How does the reference assembly resolution at runtime - if I had the reference assembly present in my application directory instead of the 'real' assembly, and not in the GAC at all, would probing continue and my AssemblyResolve event fire so that I can supply the actual assembly at runtime?
Any ideas or pointers to where I could learn more about this would be greatly appreciated.
Update: Looking around a bit, I see the .NET 3.0 'reference assemblies' do seem to have some code, and the Reference Assembly attribute was only added in .NET 4.0. So the behaviour might have changed a bit with the new runtime.
Why? For my Excel-DNA ( http://exceldna.codeplex.com ) add-in library, I create single-file .xll add-in by packing the referenced assemblies into the .xll file as resources. The packed assemblies include the user's add-in code, as well as the Excel-DNA managed library (which might be referenced by the user's assembly).
It sounds rather complicated, but works wonderfully well most of the time - the add-in is a single small file, so no installation of distribution issues. I run into (not unexpected) problems because of different versions - if there is an old version of the Excel-DNA managed library as a file, the runtime will load that instead of the packed one (I never get a chance to interfere with the loading).
I hope to make a reference assembly for my Excel-DNA managed part that users can point to when compiling their add-ins. But if they mistakenly have a version of this assembly at runtime, the runtime should fail to load it, and give me a chance to load the real assembly from resources.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
要创建参考程序集,您可以将此行添加到您的
AssemblyInfo.cs
文件中:要加载其他程序集,您可以照常从 VisualStudio 项目引用中引用它们,或者在运行时使用以下方式动态引用它们:
Assembly.ReflectionOnlyLoad()
或
Assembly.ReflectionOnlyLoadFrom()
如果您已添加引用使用 VisualStudio 到元数据/引用程序集,然后智能感知和构建您的项目将工作得很好,但是如果您尝试针对其中一个执行应用程序,您将收到错误:
因此,期望在运行时您将替换为具有相同元数据签名的真实程序集。
如果您使用
Assembly.ReflectionOnlyLoad()
动态加载了程序集,那么您只能对其执行所有反射操作(读取类型、方法、属性、属性等,但不能动态调用任何其中)。我很好奇您创建仅元数据程序集的用例是什么。我以前从未这样做过,很想知道您是否发现了它们的一些有趣用途......
To create a reference assembly, you would add this line to your
AssemblyInfo.cs
file:To load others, you can reference them as usual from your VisualStudio project references, or dynamically at runtime using:
Assembly.ReflectionOnlyLoad()
or
Assembly.ReflectionOnlyLoadFrom()
If you have added a reference to a metadata/reference assembly using VisualStudio, then intellisense and building your project will work just fine, however if you try to execute your application against one, you will get an error:
So the expectation is that at runtime you would substitute in a real assembly that has the same metadata signature.
If you have loaded an assembly dynamically with
Assembly.ReflectionOnlyLoad()
then you can only do all the reflection operations against it (read the types, methods, properties, attributes, etc, but can not dynamically invoke any of them).I am curious as to what your use case is for creating a metadata-only assembly. I've never had to do that before, and would love to know if you have found some interesting use for them...
如果您仍然对这种可能性感兴趣,我已经基于 Mono.Cecil 制作了 il-repack 项目的一个分支,它接受“/meta”命令行参数来为公共和受保护类型生成仅元数据程序集。
https://github.com/KarimLUCCIN/il-repack/tree/xna
(我在完整的 XNA 框架上尝试过它并且它的工作据我所知......)
If you are still interested in this possibility, I've made a fork of the il-repack project based on Mono.Cecil which accepts a "/meta" command line argument to generate a metadata only assembly for the public and protected types.
https://github.com/KarimLUCCIN/il-repack/tree/xna
(I tried it on the full XNA Framework and its working afaik ...)
是的,这是 .NET 4.0 的新功能。我相当确定这样做是为了避免 .NET 2.0 服务包中出现令人讨厌的版本控制问题。最好的例子是 SP2 中添加和记录的 WaitHandle.WaitOne(int) 重载。一个流行的重载,因为它避免了在 WaitOne(int, bool) 重载中猜测 *exitContext" 的正确值。问题是,当程序在早于 SP2 的 2.0 版本上运行时,程序会崩溃。这不太好隔离引用程序集可确保这种情况不会再次发生。
我认为这些引用程序集是通过从已编译程序集的副本开始创建的(就像以前版本中所做的那样)并运行。他们通过工具但是,我们无法使用该工具,bin/netfx 4.0 工具 Windows 7.1 SDK 子目录中没有任何工具可以执行此操作,因此它可能不是生产质量的工具: )
Yes, this is new for .NET 4.0. I'm fairly sure this was done to avoid the nasty versioning problems in the .NET 2.0 service packs. Best example is the WaitHandle.WaitOne(int) overload, added and documented in SP2. A popular overload because it avoids having to guess at the proper value for *exitContext" in the WaitOne(int, bool) overload. Problem is, the program bombs when it is run on a version of 2.0 that's older than SP2. Not a happy diagnostic either. Isolating the reference assemblies ensures that this can't happen again.
I think those reference assemblies were created by starting from a copy of the compiled assemblies (like it was done in previous versions) and running them through a tool that strips the IL from the assembly. That tool is however not available to us, nothing in the bin/netfx 4.0 tools Windows 7.1 SDK subdirectory that could do this. Not exactly a tool that gets used often so it is probably not production quality :)
你可能会幸运地使用 Cecil Library(来自 Mono);我认为该实现允许 ILMerge 功能,它也可能只编写元数据程序集。
我已经扫描了代码库(文档稀疏),但还没有发现任何明显的线索......
YYMV
You might have luck with the Cecil Library (from Mono); I think the implementation allows ILMerge functionality, it might just as well write metadata only assemblies.
I have scanned the code base (documentation is sparse), but haven't found any obvious clues yet...
YYMV