I need to do a "smart" detection of a generic type and return as a string, but at the moment i don't understand why delphi put some strange identification on the PTypeInfo.Name property.
What i have so far is this:
program SO_29674887;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.TypInfo;
type
TypeResolver = class
strict private
class function ReCast<T>(const AValue) : T;
public
class function Format<T>(const AValue : T) : string;
end;
Compare = class
public
class function IsEqual<A;B>(const AVal : A; BVal : B) : string;
end;
{ TypeResolver }
class function TypeResolver.ReCast<T>(const AValue): T;
begin
Result := T(AValue);
end;
class function TypeResolver.Format<T>(const AValue: T): string;
var Info : PTypeInfo;
begin
Info := TypeInfo(T);
Result := 'undefined';
if(Info.Kind = tkInteger) then
begin
if(Info.Name = GetTypeName(TypeInfo(Byte))) then
Result := IntToStr(ReCast<Byte>(AValue))
else if(Info.Name = GetTypeName(TypeInfo(ShortInt))) then
Result := IntToStr(ReCast<ShortInt>(AValue))
else if(Info.Name = GetTypeName(TypeInfo(SmallInt))) then
Result := IntToStr(ReCast<SmallInt>(AValue))
else if(Info.Name = GetTypeName(TypeInfo(Integer))) then
Result := IntToStr(ReCast<Integer>(AValue));
end;
Result := Info.Name + ':' + Result;
end;
{ Compare }
class function Compare.IsEqual<A, B>(const AVal: A; BVal: B): string;
begin
Result := Format('%s = %s', [
TypeResolver.Format<A>(AVal),
TypeResolver.Format<B>(BVal)]);
end;
var PAUSE : string;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
WriteLn(Compare.IsEqual(0, 255));
WriteLn(Compare.IsEqual(-127, 127));
WriteLn(Compare.IsEqual(0, 65535));
WriteLn(Compare.IsEqual(-32768, 32767));
WriteLn(Compare.IsEqual(0, 4294967295));
WriteLn(Compare.IsEqual(-2147483648, 2147483647));
Readln(PAUSE);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
What happens here is that instead of give me the actual type name of the integer, delphi gives me strange identifier like :2, :4, :6, etc.
For instance:
Compare.IsEqual(0, 255); //Gives Info.Name = :2, Byte
Compare.IsEqual(-127, 127); //Gives Info.Name = ShortInt, :4
Compare.IsEqual(0, 65535); //Gives Info.Name = :6, Word
Compare.IsEqual(-32768, 32767); //Gives Info.Name = SmallInt, :8
Compare.IsEqual(0, 4294967295); //Gives Info.Name = :01, Cardinal
Compare.IsEqual(-2147483648, 2147483647); //Gives Info.Name = Integer, :21
So my question is how i can find the right type to cast if it seems to me that delphi doesn't provide any clue of the actual type when he deliver those identifiers and why exactly it gives those odd identifiers.
Here's my reproduction, somewhat shorter.
{$APPTYPE CONSOLE}
uses
System.TypInfo;
type
TypeResolver = class
public
class function Format<T>(const AValue : T) : string;
end;
class function TypeResolver.Format<T>(const AValue: T): string;
var
Info: PTypeInfo;
begin
Info := TypeInfo(T);
Result := Info.Name;
end;
begin
Writeln(TypeResolver.Format(0));
Writeln(TypeResolver.Format<Byte>(0));
Writeln(TypeResolver.Format(255));
Readln;
end.
In XE2 the output is:
:3 Byte Byte
In XE6 and later the output is:
ShortInt Byte Byte
It looks as though the earlier versions of Delphi create a private type with an unspeakable name when inferring from a literal of 0
. I cannot say why that should be so. Since the behaviour has changed, one can only assume that the Embarcadero engineers made the change to fix what they deemed to be a defect.
In other words, it would seem that the behaviour that you are observing is a bug.
My hypothesis that a private type is created is backed up by this program:
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.TypInfo;
type
TypeResolver = class
public
class function Format<T>(const AValue : T) : string;
end;
class function TypeResolver.Format<T>(const AValue: T): string;
var
Info: PTypeInfo;
TypeData: PTypeData;
begin
Info := TypeInfo(T);
Result := Info.Name;
if Info.Kind=tkInteger then begin
TypeData := GetTypeData(Info);
Result := Result + ', min = ' + IntToStr(TypeData.MinValue) +
', max = ' + IntToStr(TypeData.MaxValue);
end;
end;
begin
Writeln(TypeResolver.Format(0));
Readln;
end.
On XE2 the output is:
:3, min = 0, max = 127
On XE6 the output is:
ShortInt, min = -128, max = 127
So I think that this is an issue with generic type inference, that we can probably ascribe to a bug fixed in XE6.
I don't have any advice for how you should work around this because I don't know your actual problem. That said, comparing type names is generally something that is best avoided if possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With