12

最近、D2010からDXE2に移行し、クラス内のTBytesフィールドのRTTI生成に関連するXE2およびXE3(友人のXE3でテスト済み)にショートッパーのバグ(または機能?)を見つけました。

クラス内のTBytes変数のRTTI情報が生成されないことがわかりました。

次のコードはD2010で正常に機能しますが、XE2/XE3で「エラー」というメッセージが表示されます。

誰か手がかりはありますか?これにより、すべてのソフトウェアデータシリアル化の実装が完全に破壊されます

コードをテストするには、Rttiユニットをuses宣言に追加してください

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;

FieldTypeは常にnilであるため、TBytesであるField2をチェックすると、エラーメッセージが表示されます。

D2010からRTTIで何が変更されたのかXE2の手がかりを持っている人はいますか?おそらく、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 に答える