通用整数的奇怪PTypeInfo名称

时间:2015-04-16 12:34:14

标签: delphi delphi-xe2

我需要对泛型类型进行“智能”检测并以字符串形式返回,但此刻我不明白为什么delphi会在PTypeInfo.Name属性上添加一些奇怪的标识。

到目前为止我所拥有的是:

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.

这里发生的是,而不是给我整数的实际类型名称,delphi给了我奇怪的标识符,如:2,:4,:6等。

例如:

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

所以我的问题是,如果在我看来delphi在提供这些标识符时没有提供实际类型的任何线索,以及为什么它给出那些奇怪的标识符,我将如何找到正确的类型。

2 个答案:

答案 0 :(得分:4)

对我而言,似乎正在尝试创建位于RTTI.pas

中的TValue

我使用TValue改写了你的例子。

将TMemo放在表单和以下代码上:

uses
  RTTI;

type
  TypeResolver = class
  public
    class function ReCast<T>(const AValue): T;
    class function Format<T>(const AValue: T): string;
  end;

  Compare = class
  public
    class function IsEqual<A; B>(const AValA: A; const AValB: B): string;
  end;

class function Compare.IsEqual<A, B>(const AValA: A; const AValB: B): string;
begin
  Result := Format('%s = %s', [TypeResolver.Format<A>(AValA), TypeResolver.Format<B>(AValB)]);
end;

{ TypeResolver }

class function TypeResolver.ReCast<T>(const AValue): T;
begin
  Result := T(AValue);
end;

class function TypeResolver.Format<T>(const AValue: T): string;
begin
  Result := TValue.From(AValue).TypeInfo.Name;
end;

procedure TForm13.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Add(Compare.IsEqual(0, 255));
  Memo1.Lines.Add(Compare.IsEqual(-127, 127));
  Memo1.Lines.Add(Compare.IsEqual(0, 65535));
  Memo1.Lines.Add(Compare.IsEqual(-32768, 32767));
  Memo1.Lines.Add(Compare.IsEqual(0, 4294967295));
  Memo1.Lines.Add(Compare.IsEqual(-2147483648, 2147483647));
  Memo1.Lines.Add(Compare.IsEqual(Form13, Memo1));
end;

我相信它对你来说很厚实吗?

以上是上面的输出:

ShortInt = Byte
ShortInt = ShortInt
ShortInt = Word
SmallInt = SmallInt
ShortInt = Cardinal
Integer = Integer
TForm13 = TMemo

答案 1 :(得分:3)

这是我的复制品,有点短。

{$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.

在XE2中,输出为:

:3
Byte
Byte

在XE6及更高版本中,输出为:

ShortInt
Byte
Byte

看起来早期版本的Delphi在从0的字面推断时创建了一个具有不可言名的私有类型。我不能说为什么会这样。由于行为已经改变,人们只能假设Embarcadero工程师做出改变以修复他们认为是缺陷的东西。

换句话说,您所观察到的行为似乎是一个错误。

我的假设是创建私有类型由该程序支持:

{$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.

在XE2上,输出为:

:3, min = 0, max = 127

在XE6上,输出为:

ShortInt, min = -128, max = 127

所以我认为这是泛型类型推断的问题,我们可能归因于XE6中修复的错误。

我对你应该如何解决这个问题没有任何建议,因为我不知道你的实际问题。也就是说,比较类型名称通常是最好尽可能避免的。