davepaul12
davepaul12

Reputation: 391

Delphi - Generics type constraint ordinal types

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

Answers (1)

Dalija Prasnikar
Dalija Prasnikar

Reputation: 28540

Delphi generics do not support ordinal or string type constraints.

Only allowed constraints are

  • Zero, one, or multiple interface types
  • Zero or one class type
  • The reserved word "constructor", "class", or "record"

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

Related Questions