[Lazarus] Is it possible to detect type in a generic class

Sven Barth pascaldragon at googlemail.com
Fri Dec 28 12:11:19 CET 2012


On 28.12.2012 00:58, xrfang wrote:
> Hi,
>
> Suppose I have a generic class like this:
>
> type
>    TSerie = generic class
>    public
>      procedure Append(value: T);
>    end

It should be "generic TSerie<T> = class".

>
> then, in the Append procedure can I do something like:
>
> case *typeof*(T) of
>    integer: // do something with integer
>    string: // do someting with string
>    ... ...
> end;

Don't use "TypeOf". The function you are looking for is called 
"TypeInfo" and works with every type, except Enums with jumps (e.g. 
TTestEnum = (teOne := 1, teTwo := 5)).

Here you have an example:

=== source begin ===

program tgentypes;

{$mode objfpc}

uses
   typinfo;

type
   generic TTest<T> = class
     class procedure DoSomething(aArg: T);
   end;

{ TTestClass }

class procedure TTest.DoSomething(aArg: T);
var
   ti: PTypeInfo;
begin
   ti := TypeInfo(aArg);
   case ti^.Kind of
     tkInteger:
       Writeln('Type is an integer');
     tkAString:
       Writeln('Type is an AnsiString');
     tkUString:
       Writeln('Type is a UnicodeString');
     tkBool:
       Writeln('Type is a Boolean');
     tkEnumeration:
       Writeln('Type is an enumeration');
     tkSString:
       Writeln('Type is a ShortString');
     tkClass:
       Writeln('Type is a class');
     tkObject:
       Writeln('Type is an object');
     else
       Writeln('Unhandled type: ', ti^.Kind);
   end;
end;

type
   TTestEnum = (teOne, teTwo, teThree);
   TTestObject = object

   end;

   TTestLongInt = specialize TTest<LongInt>;
   TTestAnsiString = specialize TTest<AnsiString>;
   TTestUnicodeString = specialize TTest<UnicodeString>;
   TTestShortString = specialize TTest<ShortString>;
   TTestBoolean = specialize TTest<Boolean>;
   TTestTTestEnum = specialize TTest<TTestEnum>;
   TTestTObject = specialize TTest<TObject>;
   TTestTTestObject = specialize TTest<TTestObject>;

var
   obj: TObject;
   testobj: TTestObject;
begin
   TTestLongInt.DoSomething(42);
   TTestAnsiString.DoSomething('Hello World');
   TTestUnicodeString.DoSomething('Hello World');
   TTestShortString.DoSomething('Hello World');
   TTestBoolean.DoSomething(True);
   TTestTTestEnum.DoSomething(teOne);
   TTestTObject.DoSomething(obj);
   TTestTTestObject.DoSomething(testobj);
end.

=== source end ===

For getting the exact value of the argument you need to rely on the 
information provided by the RTTI as you can't use e.g. "IntToStr(aArg)" 
in case of an integer as you'll get a compiler error when you specialize 
the class with something that is not an Integer.

Regards,
Sven





More information about the Lazarus mailing list