Как я могу проверить, поддерживает ли что-то общий интерфейс? - PullRequest
2 голосов
/ 28 октября 2011

Я использую Delphi XE2. В настоящее время у меня есть объектно-ориентированная модель, и каждый объект модели может иметь несколько валидаторов. Вот упрощенная реализация обобщенного абстрактного класса валидатора. Конкретные классы валидатора могут переопределять DoValidate, и им не нужно приводить объект модели. Валидатор используется через интерфейс IValidator.

unit ObjectBasedValidator;

interface

uses
  System.SysUtils,
  System.Generics.Collections;

type
  TModelEntity = class
  end;

type
  IValidator = interface
    procedure Validate(aEntity: TModelEntity; aResult: string);
  end;

  TValidator<T: TModelEntity> = class(TInterfacedObject, IValidator)
  private
  protected
    procedure DoValidate(aEntity: T; aResult: string); virtual; abstract;
  public
    procedure Validate(aEntity: TModelEntity; aResult: string);
  end;

implementation

{ TValidator<T> }

procedure TValidator<T>.Validate(aEntity: TModelEntity; aResult: string);
begin
  if not (aEntity is T) then
    Exit;

  DoValidate(aEntity as T, aResult);
end;

end.

Теперь я пытаюсь изменить объектную модель для интерфейса на основе. Итак, вот обновленный блок валидатора:

unit InterfaceBasedValidator;

interface

type
  IModelEntity = interface
  end;

type
  IValidator = interface
    procedure Validate(aEntity: IModelEntity; aResult: string);
  end;

  TValidator<I: IModelEntity> = class(TInterfacedObject, IValidator)
  private
  protected
    procedure DoValidate(aEntity: I; aResult: string); virtual; abstract;
  public
    procedure Validate(aEntity: IModelEntity; aResult: string);
  end;

implementation

{ TValidator<T> }

procedure TValidator<I>.Validate(aEntity: IModelEntity; aResult: string);
begin
  // The next line does not compiles
  if not (aEntity is I) then
    Exit;

  DoValidate(aEntity as I, aResult);
end;

end.

Я добавил комментарий к строке, которая не компилируется. Теперь, очевидно, для универсального типа «I» должен быть определен GUID, чтобы это работало, однако нет способа указать это требование как ограничение.

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

1 Ответ

1 голос
/ 28 октября 2011

Кажется, работает следующее:

uses
  SysUtils, TypInfo;

{ TValidator<I> }

procedure TValidator<I>.Validate(const aEntity: IModelEntity; aResult: string);
var
  intf: I;
begin
  if not Supports(aEntity, GetTypeData(TypeInfo(I))^.Guid, intf) then
    Exit;

  DoValidate(intf, aResult);
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...