【问题标题】:C# interface breakage, ABIC#接口损坏,ABI
【发布时间】:2011-06-13 14:32:32
【问题描述】:

假设我们在程序集 A.dll 的版本 1 中有 class X

class X {
    SomeType Property { set; get; }
}

然后在程序集的第 2 版中 A.dll:

class X {
    SomeType Property { set; get; }
    SomeType OtherProperty { set; get; }
}

现在假设我们有第二个程序集 B.dll 加载 A.dll 并使用 X。添加属性 OtherProperty 会破坏 ABI 吗? B.dll 会不会无法使用A.dll/X?如果不是,声明的顺序会有什么不同吗?如果属性是虚拟的,有什么不同吗?

我想我真的在问:一般的 ABI 规则是什么?我知道在发布后更改接口是一件坏事,但我真的希望能够在某些情况下添加属性,而无需添加子类。

【问题讨论】:

  • 请参阅:.NET 中 API 重大更改的明确指南 stackoverflow.com/questions/1456785/…
  • 你是如何加载 DLL 的?
  • @Mark:我有第三方客户端引用我的一些程序集。我有几个类,我想用一些属性进行扩展。我想这样做而不需要第三方重新编译他们的程序集。我可以很好地问他们,但我不愿意。它只是增加了更多的周转时间......

标签: c# .net binary-compatibility abi


【解决方案1】:

添加属性应该没问题。

如果您在自动编号的枚举的中间添加一些内容,则会出现这种情况。例如,如果您的库中有此代码:

enum Foo
{
   Bar,
   Qux
}

然后你把它改成这样:

enum Foo
{
   Bar,
   Baz,
   Qux
}

那么你还需要像这样重新编译任何代码:

if (foo == Foo.Qux)
{
    //  ...
}

【讨论】:

  • 假设我有一个返回具体类 X 的方法。如果我返回重构的接口 IX,它会破坏 ABI 吗?我认为它会,因为 IX 不存在于程序集的第一个版本中。
  • @Jörgen Sigvardsson:在大多数情况下应该没问题,但在某些极端情况下它可能不起作用。例如,如果他们使用反射来检查类,那么他们将能够看到 ABI 的任何更改,理论上它可能会破坏他们的代码。
  • @MarkByers 你能提供一些你上面答案的参考吗?
  • 如果你不想破坏现有代码,你应该只在最后添加枚举,这取决于那个枚举 - stackoverflow.com/a/12716043/2719527
【解决方案2】:

如果只是被程序集B 使用,它不会破坏兼容性。但是如果程序集B 定义了一个实现该接口的类,它将中断,因为该类没有实现新引入的属性。

【讨论】:

    【解决方案3】:

    JIT 编译器会将其中的很多内容打包,如果更改中断,这也是错误消息的来源。

    然而,您正在玩​​一个名为 DLL Hell 的非常危险的游戏。问题不在于他们不重新编译代码,而在于他们重新编译。他们最终会的。如果有一个微妙的错误,有人运行了你的安装程序的旧版本,复制了错误的文件等等,那么一切都会崩溃。代码不会运行,他们将有一个不可能的工作找出原因。这将在您进行更改很久之后发生,您也无法猜测出了什么问题,也无法帮助他们。

    不要乱来,提高 [AssemblyFileVersion] 和 [AssemblyVersion]。是的,当您更改后者时,它们必须重新编译。或者使用<bindingRedirect>,也可以,现在有可追溯记录了。

    顺便说一句:这也发生在 .NET Framework 中。 WaitHandle.WaitOne(int) 已添加到服务包中,但没有 [AssemblyVersion] 更改。程序员的目标是 .NET 2.0,但当目标机器安装了原始 2.0 时,他们的代码将无法运行。 非常痛苦。

    【讨论】:

      猜你喜欢
      • 2012-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-03
      • 2011-08-03
      • 2020-12-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多