Spring4d: Как "заставить" контейнер поверить, что класс реализует интерфейс

Я использую RemObjects DataAbstract вместе с Spring4d. RemObjects генерирует SchemaServer_Intf.pas файл, который содержит интерфейсы для каждого вида таблицы, которая существует в его схеме. Он допускает наборы данных со строгой типизацией, позволяя получить доступ к полю, используя

(aDataSet as IMyDataSet).MyField := aValue

Вот снимок одного из интерфейсов, сгенерированных DataAbstract

IEntiteType = interface(IDAStronglyTypedDataTable)
  ['{96B82FF7-D087-403C-821A-0323034B4B99}']
    { Property getters and setters }
    function GetEntiteIdValue: String;
    procedure SetEntiteIdValue(const aValue: String);
    function GetEntiteIdIsNull: Boolean;
    procedure SetEntiteIdIsNull(const aValue: Boolean);
    function GetNameValue: WideString;
    procedure SetNameValue(const aValue: WideString);
    function GetNameIsNull: Boolean;
    procedure SetNameIsNull(const aValue: Boolean);
    function GetIsSystemValue: SmallInt;
    procedure SetIsSystemValue(const aValue: SmallInt);
    function GetIsSystemIsNull: Boolean;
    procedure SetIsSystemIsNull(const aValue: Boolean);


    { Properties }
    property EntiteId: String read GetEntiteIdValue write SetEntiteIdValue;
    property EntiteIdIsNull: Boolean read GetEntiteIdIsNull write SetEntiteIdIsNull;
    property Name: WideString read GetNameValue write SetNameValue;
    property NameIsNull: Boolean read GetNameIsNull write SetNameIsNull;
    property IsSystem: SmallInt read GetIsSystemValue write SetIsSystemValue;
    property IsSystemIsNull: Boolean read GetIsSystemIsNull write SetIsSystemIsNull;
  end;

Хотя есть одна проблема. Если вы приведете dataTable примерно так:

aDataTable := IEntiteType(TDAMemDataTable.Create(nil));

У вас будет "Интерфейс не поддерживается ошибка"

Но, как только вы это сделаете:

aDataTable.LogicalName := 'EntiteType';
aDataTable.BusinessRulesId := MyBusinessRuleID;

Вы можете смело писать

aDataTable := IEntiteType(TDAMemDataTable.Create(nil));

И вы не получите никакой ошибки.

Итак, в Spring4d я подумал написать это в своем регистрационном модуле:

aContainer.RegisterType<TDAMemDataTable>.Implements<IEntiteType>.DelegateTo(
   function : TDAMemDataTable
   var aDataTable : TDAMemDataTable; 
   begin
      Result:= TDAMemDataTable.Create(nil);
      Result.LogicalName := 'EntiteType';
      Result.BusinessRulesId := MyBusinessRuleId;         
   end
) 

Но затем Spring4d выдает (с указанием причины) ошибку:

Exception 'first chance' à $762D5B68. Classe d'exception ERegistrationException avec un message 'Component type "uDAMemDataTable.TDAMemDataTable" incompatible with service type "SchemaClient_Intf.IEntiteType".'. Processus EntiteREM2.exe (3088) 

Есть ли способ переопределить эту проверку?

1 ответ

Решение

Хорошо, я нашел способ сделать это. Супер просто на самом деле:

  aContainer.RegisterType<IAddress>.DelegateTo(
    function : IAddress
    var aTable : TDAMemDataTable;
    begin
      aTable := TDAMemDataTable.Create(nil);
      aTable.LogicalName := nme_Address;
      aTable.BusinessRulesID := RID_Address;
      Result := aTable as IAddress;
    end
  );

Кроме того, для людей, заинтересованных в элегантной регистрации многих столов:

aContainer.RegisterType<IAddress>.DelegateTo(TableConfigurator.GetTableDelegate<IAddress>(nme_Address, RID_Address));
// Registering other tables here...

Просто создайте некоторый класс Helper с помощью этого метода:

class function TableConfigurator.GetTableDelegate<T>(aLogicalName, aBusinessRulesId: string): TActivatorDelegate<T>;
begin
  Result := (function: T
    var
      aTable: TDAMemDataTable;
    begin
      aTable := TDAMemDataTable.Create(nil);
      aTable.LogicalName := aLogicalName;
      aTable.BusinessRulesID := aBusinessRulesId;
      Result := T(TValue.From(aTable).AsInterface);
    end);
end;
Другие вопросы по тегам