Версия интерфейса

Где я работаю, мы только что закончили выпуск функции, использующей dll, которая в значительной степени полагается на интерфейсы. DLL и все клиентские приложения написаны в Delphi. Нет необходимости в регистрации. Эта dll не является надлежащим com-сервером. Единственное ограничение состоит в том, что устройство, содержащее интерфейс, доступно как для dll, так и для клиентских приложений. Это позволило нам передавать сложные данные в и из приложений, использующих эту dll, без необходимости прибегать к указателям на записи, массивам или сигнатурам с чрезвычайно жирной функцией и без багажа, который будет вводить bpl или полностью совместимый COM-сервер.

Похоже, что она решила серьезную проблему, с которой у нас не было ни одной стороны. К сожалению, есть недостаток. Любое изменение интерфейса после его выпуска требует последующей перекомпиляции любых пользователей этого интерфейса. Это хорошо для проектов, которые являются частью одного и того же цикла выпуска, но некоторые из наших проектов имеют разные расписания выпуска.

Я исследовал это немного, и похоже, что обычной практикой является введение нового интерфейса, который наследуется от ранее выпущенного интерфейса, а не изменяет оригинальный интерфейс.

type
  IOriginalInterface = interface
  ['{8B598EC1-AD92-4144-A1BE-9062C5EA0748}']
    procedure DoSomething;
  end;

  INewInterface = interface(IOriginalInterface)
  ['{DD9D9DE0-0F87-4BC5-803C-74C8AB0F3E39}']
    procedure DoSomethingElse;
  end;

Это гарантирует, что старые исполняемые файлы, скомпилированные с использованием исходного интерфейса, продолжают работать.

Я заметил, что с открытыми инструментами RAD Studio api интерфейсы переименовываются всякий раз, когда вводится новый. Поэтому вместо того, чтобы давать новейшему интерфейсу новое имя, новый интерфейс получает исходное имя интерфейса, а оригинальный интерфейс переименовывается.

type
  IOldInterface = interface
  ['{8B598EC1-AD92-4144-A1BE-9062C5EA0748}']
    procedure DoSomething;
  end;

  IOriginalInterface = interface(IOldInterface)
  ['{DD9D9DE0-0F87-4BC5-803C-74C8AB0F3E39}']
    procedure DoSomethingElse;
  end;

Это, очевидно, хорошо работало для команды RAD Studio, а также сторонних поставщиков расширений. Это гарантирует, что любые клиенты, которые будут перекомпилированы, будут использовать последний интерфейс без каких-либо изменений кода. Я предполагаю, что это работает, потому что имя не имеет значения, и после компиляции кода все, что остается, - это определение интерфейса, которое разрешено с помощью GUID.

Сказав все это, это хорошее решение проблемы с версией интерфейса, с которой мы сталкиваемся сейчас? Есть ли какие-либо другие вопросы, о которых я должен знать?

Ответ 1

Позвольте мне объяснить логику того, что вы наблюдали с помощью ToolsAPI, и затем можете определить, как это относится к вашей ситуации. Ваши рассуждения очень близки.

Для интерфейсов, предназначенных для использования плагинами и расширениями IDE, вы правильно указываете, каким образом интерфейсы управляются версиями и называются. Идея состоит в том, что существующий код будет ссылаться на конкретное имя интерфейса и потому, что все существующие методы также существуют на этом интерфейсе. Поскольку старый код просто не может ссылаться на какие-либо новые методы, безопасно включать их в новый интерфейс.

Однако, если вы посмотрите внимательно, для интерфейсов, которые должны быть реализованы с помощью расширения плагина или IDE, вы увидите, что обратное верно. Новые интерфейсы получают новые имена, а все старые существующие интерфейсы остаются неизменными. Это связано с тем, что в качестве исполнителя интерфейса вы должны реализовать все методы интерфейса. Существующий код, по определению, не будет реализовывать новые методы. Когда IDE необходимо вызвать метод, реализованный пользователем, он всегда будет выполнять этот вызов, запросив версию интерфейса, на которой был введен этот метод, который может быть не самой последней версией интерфейса. По этой причине нужно перечислить все интерфейсы предков как реализуемые в классе реализации.

Итак, правило для IDE ToolsAPI - это то, что для интерфейсов, которые используют плагины, самая новая версия интерфейса всегда получает неверсированное имя. Для интерфейсов, реализуемых плагином, новые интерфейсы всегда получают новое имя.