Delphi XE2 RTTI сломан?
недавно я мигрировал из D2010 в DXE2 и обнаружил ошибку showstopper (или функцию?) в XE2 и XE3 (проверено в my friend XE3), связанных с генерацией RTTI для полей TBytes внутри классов.
Я обнаружил, что информация RTTI для переменной TBytes внутри класса никогда не генерируется.
следующий код хорошо работает в 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;
сообщение об ошибке будет отображаться при проверке Field2, который является TBytes, потому что тип поля всегда равен нулю!!!
кто-нибудь имеет представление о том, что изменилось в RTTI с D2010 do XE2? Может быть, потому, что тип TBytes был изменен с массива байтов на общий массив?
2 ответов
Это известная проблема, которая была исправлена в XE3. к сожалению, обновление-единственный способ исправить это; исправления ошибок обычно не переносятся обратно.
EDIT: или нет. По-видимому, это на самом деле не исправлено, так как это все еще происходит в XE3. Сообщить об этом как о новом случае и упомянуть 103729, вероятно, было бы лучшим вариантом действий.
вы можете исправить эту ошибку (на самом деле это не та же ошибка, что и упомянутый Мейсон).
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