Reputation: 2043
I am using Delphi XE2. Currently I have an object based model and each model object can have multiple validators. Here is the simplified implementation of the validator generic abstract class. The concrete validator classes can override DoValidate and they do not have to cast the model object. The validator gets used using its 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<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.
Now I am trying to change the object model to interface based. So here is the updated validator unit:
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 put a comment to the line which does not compile. Now obviously the "I" generic type would need to have a GUID defined for this to work, however there is no way to specify this requirement as a constraint.
A possible workaround could be to not to use a generic abstract class and cast the interface in the validator, but I am just wondering if someone has an idea how to do this without casting.
Upvotes: 2
Views: 381
Reputation: 37221
The following seems to work:
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;
Upvotes: 1