为什么 COM 接口契约是不可变的?

Why is the COM interface contract immutable?

我在谷歌上搜索了很多,发现没有人关心解释为什么 COM 接口是不可变的,这很奇怪。我想您无法从 COM 接口中删除任何方法的原因是因为依赖该接口的客户端会遇到错误,这是不好的。但是,为什么向界面添加新功能会改变其中的任何一个呢?这与底层 vtable 有关系吗?

如果添加方法,则使用该方法的较新客户端在使用组件的旧版本时会失败。

组件的旧版本不会有新方法,除非您专门添加代码来实现它,重建组件,然后在使用该组件的所有计算机上重新安装该组件。

如果较新版本的客户端尝试在没有该方法的旧版本组件上调用新方法,则会发生未定义的行为(可能会崩溃,但也可能会导致静默数据损坏)。新客户端将尝试通过构建旧客户端时不存在的 vtable 中的指针条目调用方法,因此旧客户端将在此位置具有一些不相关的值。

当然,如果您同时控制客户端和组件并将它们部署在一起,这对您来说不是问题,但 COM 设计用于比这更广泛的用例。

COM 有一个非常严重的 DLL 地狱问题。几个基本原因:

  • 参与编写服务器和客户端代码的程序员彼此很少认识,不一起工作并且有自己的发布时间表。
  • 默认情况下,注册服务器是在计算机范围内进行的,这会影响依赖于服务器的每个客户端程序。使用无注册清单的隔离 COM 是一种解决方法。
  • 早期绑定 COM(使用 v-table)非常高效,但对 v-table 更改极度不耐受。当客户端代码简单地调用完全错误的函数或传递错误的参数时,很难诊断不匹配。通过 IDispatch 进行后期绑定调用是一种解决方法,但速度较慢。
  • COM 程序员作弊的动机非常强烈,更改接口 {guids} 会导致脾气暴躁的客户端程序员和尴尬的支持电话。使接口向后兼容相对容易,使其向前兼容永远行不通。只改界面guid才是真正安全的。
  • 部署 COM 服务器通常是客户的职责,他们通常对服务器的了解不够,无法解决和纠正问题。

这些都是通用的版本控制问题,许多运行时实现都遭受了不同程度的痛苦。 COM 的一个特殊优势是您可以对其进行一些处理。更改 {guids} 后,很多脏东西就烟消云散了。