Hoe kan ik controleren of iets een generieke interface ondersteunt?

Ik gebruik Delphi XE2. Momenteel heb ik een objectgebaseerd model en elk modelobject kan meerdere validators bevatten. Hier is de vereenvoudigde implementatie van de generieke abstracte klasse validator. De concrete validatieklassen kunnen DoValidate overschrijven en ze hoeven niet het modelobject te casten. De validator wordt gebruikt met behulp van de IValidator-interface.

unit ObjectBasedValidator;

interface

uses
  System.SysUtils,
  System.Generics.Collections;

type
  TModelEntity = class
  end;

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

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

implementation

{ TValidator }

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

  DoValidate(aEntity as T, aResult);
end;

end.

Nu probeer ik het objectmodel te veranderen in interface-gebaseerd. Dus hier is de bijgewerkte validatoreenheid:

unit InterfaceBasedValidator;

interface

type
  IModelEntity = interface
  end;

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

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

implementation

{ TValidator }

procedure TValidator.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.

Ik zet een commentaar op de regel die niet compileert. Het is duidelijk dat het "I" -generatieve type een GUID moet hebben die hiervoor is gedefinieerd, maar er is geen manier om deze vereiste als een beperking te specificeren.

Een mogelijke oplossing kan zijn om geen generieke abstracte klasse te gebruiken en de interface in de validator te plaatsen, maar ik vraag me af of iemand een idee heeft hoe dit te doen zonder te casten.

2
Om dit te laten werken, denk ik dat er een manier moet zijn om een ​​ heeft GUID -beperking op te geven.
toegevoegd de auteur David Heffernan, de bron

1 antwoord

Het volgende lijkt te werken:

uses
  SysUtils, TypInfo;

{ TValidator }

procedure TValidator.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;
1
toegevoegd
Ik zou de RTL-code moeten doorlopen om zeker te zijn, maar ik vermoed dat het aanvragen van een nul-GUID een algemene Intervenerationele/IUnknown -interfacewijzer zou retourneren als er al iets was.
toegevoegd de auteur Remy Lebeau, de bron
Wat is de foutmodus wanneer I geen GUID heeft?
toegevoegd de auteur David Heffernan, de bron
Je kunt alleen raden wat er in dat geval in intf zou verschijnen.
toegevoegd de auteur David Heffernan, de bron
De GUID is null ({00000000-0000-0000-0000-000000000000}) maar interessant ondersteunt nog steeds True.
toegevoegd de auteur Ondrej Kelle, de bron