Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2012-12

Is it possible to detect type in a generic class

5 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

xrfang

Hi,

Suppose I have a generic class like this:

type?
? TSerie = generic class
? public
? ? procedure Append(value: T); ??
? end

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;

Thanks!
Shannon
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20121228/dd08cf25/attachment-0001.html>

Reply by email

Alexander Klenin
to xrfang
xrfang wrote 5 lines
case typeof(T) of integer: // do something with integer string: // do someting with string ... ... end;

Call an overloaded procedure.

Alexander S. Klenin

Reply by email

Sven Barth
to xrfang: Suppose I have a generic class like this: type? ? TSerie = generic class ? public ? ?…
xrfang wrote 9 lines
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".

Show quoted text 8 lines
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

Reply by email

xrfang
to Sven Barth

Thanks a lot for the code sample. ? TypeInfo will be useful, but for now I give up this route, because I hope it to be more "elastic" by providing an Append() method if T is an array of something, otherwise no Append() method, this seems can only be achieved by inheritance instead of generics.

? ?, 12? 28, 2012 at 7:11 ???Sven Barth ???

xrfang wrote 9 lines
Hi, Suppose I have a generic class like this: type TSerie = generic class public procedure Append(value: T); end

It should be "generic TSerie = class".

Show quoted text 8 lines
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 = 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;
TTestAnsiString = specialize TTest;
TTestUnicodeString = specialize TTest;
TTestShortString = specialize TTest;
TTestBoolean = specialize TTest;
TTestTTestEnum = specialize TTest;
TTestTObject = specialize TTest;
TTestTTestObject = specialize TTest;
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

Reply by email