Безопасный вызов интерфейса, реализация не безопасного вызова

У меня есть интерфейс для использования по технологии DCOM.
Все методы, определенные в интерфейсе, имеют директиву safecall.
Однако на стороне клиента я хочу отразить этот объект в TObject, чтобы избежать перехода через интерфейс каждый раз, когда мне нужно их прочитать.

Например

IMyInterface = interface(IDispatch);
  procedure Set_fA(const Value: WideString); safecall;
  function Get_fA: WideString; safecall;
end;

Этот интерфейс реализуется директивой TAutoIntfObject, в данном случае реализация сохраняет директиву safecall.

TMyAuto = class(TAutoIntfObject, IMyInterface)
private
  fA : WideString;  
public
  procedure Set_fA(const Value: WideString); safecall;
  function Get_fA: WideString; safecall;
end;

Но теперь с TObject, если я удалю безопасный вызов:

TMyObject = class(TObject, IMyInterface)
private
  fA : WideString;  
public
  procedure Set_fA(const Value: WideString); //??
  function Get_fA: WideString; //??
  procedure CopyFromServer(Original: OleVariant); 
end;

Компилятор выдает следующую ошибку: "Объявление Set_fA отличается от объявления в интерфейсе IMyObject"

Обычно я могу использовать TObject с безопасным вызовом, не будет ли проблем, если я буду продолжать в том же духе?
Есть ли случай, когда безопасный вызов имеет значение, а не cdecl?

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


person EProgrammerNotFound    schedule 26.07.2013    source источник
comment
TMyObject не реализует IDispatch   -  person David Heffernan    schedule 27.07.2013


Ответы (2)


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

TMyObject = class(TObject)
private
  fServerInterface: IMyInterface;
  fDataLoaded: boolean;

  //cached data
  fA : WideString;  
  procedure LoadAllData;
public
  procedure Set_fA(const Value: WideString);
  function Get_fA: WideString;
end;

function TMyObject.Get_fA: WideString;
begin
   if not fDataLoaded then
      LoadAllData;
   result := fA;          
end;

procedure TMyObject.Set_fA(const Value: WideString);
begin
   fServerInterface.Set_fA(value);
   fA := value;
end;

procedure TMyObject.LoadAllData;
begin
   fA := fServerInterface.Get_fA;
   fDataLoaded := true;
end;

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

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

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

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

Какое решение вы выберете, зависит от вас. Тем не менее, убедитесь, что вы действительно хорошо проанализировали ситуацию, прежде чем принять решение.

person Mason Wheeler    schedule 26.07.2013
comment
Что вы предлагаете в этой ситуации? Как избежать перехода на сервер каждый раз, когда мне нужно прочитать свойства интерфейса? - person EProgrammerNotFound; 27.07.2013
comment
@MatheusFreitas: Хорошо. Я переписал свой ответ, чтобы решить ваши проблемы. - person Mason Wheeler; 27.07.2013
comment
Я хотел реализовать интерфейс, чтобы убедиться, что все методы реализованы, но, поскольку он требует безопасного вызова, я подумал, не вызовет ли это каких-либо проблем. - person EProgrammerNotFound; 29.07.2013
comment
@MatheusFreitas: Нет, safecall компилятор просто создает оболочку вокруг ваших методов, которая прозрачно преобразует соглашения об обработке ошибок COM и исключения Delphi. Это не должно вызывать у вас никаких проблем, особенно если ваши реализации не вызывают никаких исключений. - person Mason Wheeler; 29.07.2013

Давай, верни safecall к своим методам. Интерфейс этого требует. Интерфейс также потребует, чтобы вы реализовали остальные методы, представленные IDispatch, поскольку TObject не реализует их сам.

Safecall и cdecl — это совершенно разные соглашения о вызовах; они никогда не взаимозаменяемы. Они различаются тем, кто очищает стек, и различаются тем, как ошибки передаются между вызывающим и получателем. Интерфейс указывает один, поэтому вы не можете выбрать что-то другое при его реализации.

person Rob Kennedy    schedule 26.07.2013