【问题标题】:How can I check whether something supports a generic interface?如何检查某些东西是否支持通用接口?
【发布时间】:2011-10-27 20:28:46
【问题描述】:

我正在使用 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 才能工作,但是没有办法将此要求指定为约束。

一种可能的解决方法是不使用通用抽象类并在验证器中强制转换接口,但我只是想知道是否有人知道如何在不强制转换的情况下做到这一点。

【问题讨论】:

  • 为此,我认为需要某种方式来指定 has GUID 约束。

标签: delphi generics interface


【解决方案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;

【讨论】:

  • I 没有 GUID 时的故障模式是什么?
  • GUID 为 null ({00000000-0000-0000-0000-000000000000}) 但有趣的是 Supports 仍然返回 True。
  • 人们只能猜测在这种情况下intf 中会出现什么。
  • 我必须单步执行 RTL 代码才能确定,但​​我猜想请求空 GUID 会返回一个通用的 IInterface/IUnknown 接口指针(如果有的话)。
猜你喜欢
  • 2012-06-04
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 2012-05-11
  • 2012-03-12
  • 1970-01-01
相关资源
最近更新 更多