在.NET 2.0中使用扩展属性来避免陷入Catch-22困境

9

如何让一个单独的.NET程序集同时支持2.0、3.0、3.5、4.0和4.5版本,并为C#和VB.NET消费者提供扩展方法?

标准建议是添加以下内容:

namespace System.Runtime.CompilerServices
{
  public sealed class ExtensionAttribute : Attribute { }
}

这是更多一位微软员工提出的方法,甚至被MSDN杂志推荐。许多博客作者称其为“没有负面影响”。除了会导致面向.NET 3.5或更高版本的VB.NET项目编译器错误外,这种方法广受好评。Microsoft.Core.Scripting.dll的作者们已经解决了这个问题,将“public”改为“internal”。
namespace System.Runtime.CompilerServices
{
  internal sealed class ExtensionAttribute : Attribute { }
}

这似乎解决了VB兼容性问题。

因此,我信任地采用了该方法来处理广泛使用的ImageResizing.Net库的最新版本(3.2.1)。

但是,然后,我们开始为某些针对.NET 3.5+的用户随机遇到这个编译器错误(原始报告)。

Error 5 Missing compiler required member
'System.Runtime.CompilerServices.ExtensionAttribute..ctor'

由于 MSBuild/VisualStudio 编译器在解析命名冲突时显然不会考虑作用域规则,并且程序集引用的顺序起着非常重要但未被全面记录的作用,因此我不完全理解为什么以及何时会发生这种情况。
有一些笨拙的变通方法,例如更改程序集命名空间、重新创建项目文件、删除/重新添加 System.Core 并调整 .NET Framework 的目标版本。不幸的是,这些变通方法都不是 100% 可行的(除了定义别名,但这是无法接受的痛苦)。
如何在以下情况下解决该问题:
  1. 保持对程序集内扩展方法使用的支持,
  2. 保持对 .NET 2.0/3.0 的支持,
  3. 不需要为每个 .NET Framework 版本使用多个程序集。
或者,是否有一个热修复程序可以使编译器注意作用域规则?
SO 上相关的问题并没有回答这个问题。

呃,你的赏金缺少一个零。最好与微软支持联系,尽管他们很可能会以“不支持”为由驳回它。 - Hans Passant
1个回答

2
我们在IronPython中遇到了相同的问题。最终,我们将自定义版本的ExtensionAttribute移动到了自己的程序集中。这样,客户可以选择引用我们的自定义ExtensionAttribute程序集或System.Core程序集,但不能同时引用两者!
另一个棘手的问题是,即使您的项目中没有引用它,您也必须始终部署ExtensionAttribute程序集。公开扩展方法的项目程序集将具有对该自定义ExtensionAttribute程序集的assemblyref引用,因此如果找不到它,CLR会感到不安。
考虑到.NET 2.0支持的硬性要求,我认为最好的选择是根本不使用扩展方法。我不熟悉ImageResizer项目,但听起来这是ImageResizer的最近变化。将扩展方法更改为传统的静态方法有多可行?我们实际上曾经考虑过这个问题,但对于IronPython / DLR来说不可行(当时我们已与LINQ合并,并且LINQ在其整个存在期间都广泛使用扩展方法)。

感谢您更新文章并提供链接!我认为Newtonsoft.Json也遇到了我们的噩梦...太多博客声称没有后果,当我在半打博客上读到同样的事实时,我就认为这是真的! - Lilith River
仅仅是个想法,我们能否通过类型转发来解决问题? - Pavel Savara
请注意,我在我的博客上添加了一份详细的解释:http://devhawk.net/2012/06/20/ambiguous-extensionattribute-errors/ - DevHawk
更新了@DevHawk提到的链接 http://devhawk.net/blog/2008/10/21/the-fifth-assemblyhttp://devhawk.net/blog/2012/6/21/ambiguous-extensionattribute-errors - MarkP

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