Rtti манипулирование данными и согласованность в Delphi 2010 - PullRequest
3 голосов
/ 05 мая 2010

У кого-нибудь есть идея, как сделать TValue, используя ссылку на исходные данные? В моем проекте сериализации я использую (как предложено в XML-Serialization ) универсальный сериализатор, который хранит TValues ​​во внутренней древовидной структуре (аналогично MemberMap в примере).

Это дерево элементов также следует использовать для создания формы динамической настройки и манипулирования данными. Моя идея состояла в том, чтобы определить свойство для данных:

TDataModel <T> = class
  {...}
  private
    FData : TValue;
    function GetData : T;
    procedure SetData (Value : T);
  public
    property Data : T read GetData write SetData;
end;

Реализация методов GetData, SetData:

procedure TDataModel <T>.SetData (Value : T);

begin
FData := TValue.From <T> (Value);
end;

procedure TDataModel <T>.GetData : T;

begin
Result := FData.AsType <T>;
end;

К сожалению, метод TValue.From всегда создает копию исходных данных. Таким образом, всякий раз, когда приложение вносит изменения в данные, DataModel не обновляется, и, наоборот, если я изменяю свою DataModel в динамической форме, на исходные данные это не влияет. Конечно, я всегда мог использовать свойство Data до и после изменения чего-либо, но так как я использую много Rtti внутри моей DataModel, я действительно не хочу делать это в любое время.

Возможно, у кого-то есть лучшее предложение?

Ответы [ 2 ]

4 голосов
/ 05 мая 2010

TValue предназначен для хранения любых данных в очень компактной форме, он не предназначен для эмуляции «указателя». Взгляните на модуль RTTI.pas: TValue - это ЗАПИСЬ, в которой есть только один элемент данных типа TValueData. TValueData сама по себе является вариантом записи.

Взглянув на TValueData, вы увидите, что он НЕ содержит ничего, кроме минимального объема данных: невозможно узнать, откуда пришло это TValue.

Решение: не держите TValue в ваших структурах, замените его на пару TRttiField + TObject. Когда вам нужно TValue, используйте TRttiField.GetValue (Instance), когда вы хотите установить значение, используйте TRttiField.SetValue (Instance, AValue: TValue).

0 голосов
/ 05 мая 2010

Спасибо Cosmin за вашу помощь, решение состоит не в том, чтобы сохранить TValue в структуре, а в использовании указателя на данные и использовании методов GetValue, SetValue поля или свойства.

Итак, вот как я решил это в моем общем классе:

TDataModel <T> = class
  private
    FType     : PTypeInfo;
    FInstance : Pointer;
  public 
    constructor Create (var Data : T);
    procedure ShowContent;
  end;

constructor TDataModel <T>.Create (var Data : T);

begin
FType := TypeInfo(T);
if FType.Kind = tkClass then
  FInstance := TObject (Data)
else if FType.Kind = tkRecord then
  FInstance := @Data;
end;

procedure TDataModel <T>.ShowContent;
var 
  Ctx   : TRttiContext;
  Field : TRttiField;

begin
for Field in Ctx.GetType (FType).GetFields do
  Writeln (Field.GetValue (FInstance).ToString);
end;

Теперь вы можете изменить поля, используя DataModel или исходный класс записи.

...