我最近从D2010迁移到了DXE2,并在XE2和XE3(在我的朋友XE3中测试过)中发现了一个showstopper错误(或功能?),它与类内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总是为零!!!
有没有人知道D2010对XE2的RTTI有什么变化?也许是因为TBytes类型从Byte数组更改为泛型数组?
答案 0 :(得分: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上测试
答案 1 :(得分:9)
这是a known issue that was fixed in XE3.不幸的是,升级是获得修复的唯一方法;错误修复通常不会被移植回来。
编辑:或不。显然这实际上并没有修复,因为它仍然出现在XE3中。将其作为新案例报告并提及103729可能是最佳行动方案。