如何检查某些东西是否支持通用接口?

时间:2011-10-27 20:28:47

标签: delphi generics interface

我正在使用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 个答案:

答案 0 :(得分:1)

以下似乎有效:

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;