12

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

我发现永远不会生成类中 TBytes 变量的 RTTI 信息。

以下代码在 D2010 中运行良好,但在 XE2/XE3 中显示消息“错误”

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

要测试代码,请将 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;

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

有人知道从 D2010 到 XE2 的 RTTI 发生了什么变化吗?可能是因为 TBytes 类型从 Byte 数组更改为泛型数组?

4

2 回答 2

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;

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

type
  TMyClass = class
  private
    Field1: Integer;
    [FixTypeInfo(TypeInfo(TBytes))]
    Field2: TBytes;
  end;

并确保调用了 FixFieldType 例程:

initialization
  FixFieldType(TypeInfo(TMyClass));

在 XE 上测试

于 2012-10-02T09:27:13.510 回答
9

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

编辑:或者不是。显然这实际上并没有解决,因为它仍然出现在 XE3 中。将其报告为新案例并提及 103729 可能是最好的做法。

于 2012-10-01T19:07:29.327 回答