我正在使用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才能起作用,但是无法将这一要求指定为约束。

一个可能的解决方法可能是不使用泛型抽象类并在验证器中强制转换接口,但是我只是想知道是否有人对如何不强制转换进行了了解。

最佳答案

以下似乎有效:

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;

07-24 19:19
查看更多