Reputation: 391
I want to bound type T for both types Integer and string:
interface
type
MyFactory<T> = class
public
function createGenerator<T:Integer,string>:IGenerator<T>;
end;
But the compiler gives: '(..) E2510 Type 'Integer' is not a valid constraint'. How can I restrict type T to be a Integer or string? Or is this a problem because I am using ordinal types?
Upvotes: 2
Views: 2644
Reputation: 28540
Delphi generics do not support ordinal or string type constraints.
Only allowed constraints are
Delphi Constraints in Generics
I can only guess what exactly you are trying to accomplish but following code may give you some ideas
IGenerator<T> = interface
function Generate: T;
end;
TStringGenerator = class(TInterfacedObject, IGenerator<string>)
public
function Generate: string;
end;
TIntegerGenerator = class(TInterfacedObject, IGenerator<integer>)
public
function Generate: integer;
end;
MyFactory<T> = class
public
class function createGenerator<T>: IGenerator<T>;
end;
class function MyFactory<T>.createGenerator<T>: IGenerator<T>;
var
gs: IGenerator<string>;
gi: IGenerator<integer>;
begin
if TypeInfo(T) = TypeInfo(string) then
begin
gs := TStringGenerator.Create;
Result := IGenerator<T>(gs);
end
else
if TypeInfo(T) = TypeInfo(integer) then
begin
gi := TIntegerGenerator.Create;
Result := IGenerator<T>(gi);
end
else Result := nil;
end;
function TIntegerGenerator.Generate: integer;
begin
Result := 10;
end;
function TStringGenerator.Generate: string;
begin
Result := 'abc';
end;
var
i: integer;
s: string;
i := MyFactory<integer>.createGenerator<integer>.generate;
s := MyFactory<string>.createGenerator<string>.generate;
TTypeKind can also be used instead of TypeInfo
for determining type. Main difference is that TypeInfo
gives you exact type used, while TTypeKind
covers all types that fall into certain category. While TTypeKind
gives more flexibility, it should be used with caution if code depends on typecasts. For instance tkInteger
covers both integer
and byte
types, and typecast can cause errors.
class function MyFactory<T>.createGenerator<T>: IGenerator<T>;
var
gs: IGenerator<string>;
gi: IGenerator<integer>;
begin
case PTypeInfo(TypeInfo(T)).Kind of
tkUString :
begin
gs := TStringGenerator.Create;
Result := IGenerator<T>(gs);
end;
tkInteger :
begin
gi := TIntegerGenerator.Create;
Result := IGenerator<T>(gi);
end
else Result := nil;
end;
end;
Upvotes: 9