Delphi XE2 RTTI坏了吗?

Eri*_*ric 12 delphi delphi-2010 delphi-xe2 delphi-xe3

我最近从D2010迁移到了DXE2,并在XE2和XE3(在我的朋友XE3中测试)中发现了与类内TBytes字段的RTTI生成相关的showstopper bug(或功能?).

我发现从不生成类中TBytes变量的RTTI信息.

以下代码在D2010中运行良好,但在XE2/XE3中显示消息"Error"

有没有人有任何线索?这将彻底打破我们所有的软件数据序列化实现

要测试代码,请将Rtti单位添加到使用声明中

type

  TMyClass = class
  public
    Field1: Integer;
    Field2: TBytes;
  end;


procedure TForm2.Button1Click(Sender: TObject);
var
  i: Integer;
  Data: TMyClass;
  Rtti: TRttiContext;
  RttiClassType: TRttiInstanceType;
begin

  Data := TMyClass.Create;
  try

    // Get the context
    Rtti := TRttiContext.Create;
    try

      // Get the type for the class
      RttiClassType := TRttiInstanceType(Rtti.GetType(Data.ClassInfo));

      // Check the fields
      for i := 0 to High(RttiClassType.GetFields) do
      begin

        // Check the field type
        if not Assigned(RttiClassType.GetFields[i].FieldType) then
          ShowMessage('Error');

      end;

    finally
      Rtti.Free;
    end;

  finally
    Data.Free;
  end;

end;
Run Code Online (Sandbox Code Playgroud)

检查Field2是TBytes时将显示错误消息,因为FieldType始终为零!

有没有人知道从D2010到XE2的RTTI有什么变化?也许是因为TBytes类型从Byte数组更改为泛型数组?

Ste*_*nke 15

你可以修复这个错误(它实际上与Mason提到的错误不同).

type
  FixTypeInfoAttribute = class(TCustomAttribute)
  public
    FTypeInfo: PPTypeInfo;
    constructor Create(TypeInfo: PTypeInfo);
  end;

procedure FixFieldType(TypeInfo: PTypeInfo);
var
  ctx: TRttiContext;
  t: TRttiType;
  f: TRttiField;
  a: TCustomAttribute;
  n: Cardinal;
begin
  t := ctx.GetType(TypeInfo);
  for f in t.GetFields do
  begin
    for a in f.GetAttributes do
    begin
      if (a is FixTypeInfoAttribute) and f.ClassNameIs('TRttiInstanceFieldEx') then
      begin
        WriteProcessMemory(GetCurrentProcess, @PFieldExEntry(f.Handle).TypeRef,
          @FixTypeInfoAttribute(a).FTypeInfo, SizeOf(Pointer), n);
      end;
    end;
  end;
end;

constructor FixTypeInfoAttribute.Create(TypeInfo: PTypeInfo);
begin
  FTypeInfo := PPTypeInfo(PByte(TypeInfo) - SizeOf(Pointer));
end;
Run Code Online (Sandbox Code Playgroud)

然后将属性添加到类定义中:

type
  TMyClass = class
  private
    Field1: Integer;
    [FixTypeInfo(TypeInfo(TBytes))]
    Field2: TBytes;
  end;
Run Code Online (Sandbox Code Playgroud)

并确保调用FixFieldType例程:

initialization
  FixFieldType(TypeInfo(TMyClass));
Run Code Online (Sandbox Code Playgroud)

在XE上测试过

  • @David:添加了构造函数实现。并且不存在名称不匹配,因为您可以省略属性上的“Attribute”部分。 (2认同)

Mas*_*ler 9

这是在XE3中修复的已知问题. 不幸的是,升级是获得修复的唯一方法; 错误修复通常不会被移植回来.

编辑:或不.显然这实际上并没有修复,因为它仍然出现在XE3中.将其报告为新案例并提及103729可能是最佳行动方案.

  • 它确实有效......问题是我使用{$ RTTI EXPLICIT METHODS([])PROPERTIES([])FIELDS([vcPublic])}以便不为私有类字段生成RTTI ......并使用vcPublic它不会为公共TBYtes字段生成RTTI ... (2认同)
  • @Eric:"解决方案"的工作原理是根本不为字段生成任何RTTI.不为TBytes生成类型是一个不同的问题; 这是一个编译器级别的问题.如果它未在XE3中修复,请尝试将此问题作为新问题发布,并以您的代码为例,并提及其他QC案例. (2认同)
  • 通过用TArray <Byte>代替TBytes,它将产生RTTI (2认同)
  • 应该清除TBytes.`TArray <Byte>`是声明这种类型的规范方法. (2认同)