Почему не будет вызван опубликованный метод записи свойств Int64 - потоковая передача компонентов - PullRequest
1 голос
/ 05 сентября 2011

Вот простой тест, демонстрирующий проблему, с которой я сталкиваюсь в проекте при использовании Delphi 2007. Я использую класс TComponent для хранения различных состояний компонента. Но методы записи свойств Int64 никогда не вызываются (задается только поле назначения). Так что нельзя полагаться на писателя для обновления графического интерфейса пользователя TList или подобных вещей ...

Например:

TTestClass = Class(TComponent)
  Private
    Fb: Int64;
    Fa: Integer;
    Procedure SetFa(Const Value: Integer);
    Procedure SetFb(Const Value: Int64);
  Published
    Property a: Integer Read Fa Write SetFa;
    Property b: Int64 Read Fb Write SetFb;
  Public
    Procedure SaveInstance(Var Str: TStream);
    Procedure LoadInstance(Var Str: TStream);
    Procedure ReallyLoadInstance(Var Str: TStream);
    Procedure Assign(Source: TPersistent); Override;
  End;

TForm1 = Class(TForm)
  Button1: TButton;
  Button2: TButton;
  Button3: TButton;
  Procedure Button1Click(Sender: TObject); // test: 1st step, save the class
  Procedure Button2Click(Sender: TObject); // test: 2nd step, try and fail to reload
  Procedure Button3Click(Sender: TObject); // test: 3rd step, successfull reloading
Private
  TestClass: TTestClass;
  Str: TStream;
Public
  Constructor Create(AOwner: TComponent); Override;
  Destructor Destroy; Override;
End;

Var
  Form1: TForm1;

Implementation
{$R *.dfm}

Procedure TTestClass.SetFa(Const Value: Integer);
Begin
  Fa := Value;
  ShowMessage('ok for "simple types"....');
End;
Procedure TTestClass.SetFb(Const Value: Int64);
Begin
  Fb := Value;
  ShowMessage('and for the others');
End;
Procedure TTestClass.SaveInstance(Var Str: TStream);
Begin
  Str.Position := 0;
  Str.WriteComponent( Self );
End;
Procedure TTestClass.Assign(Source: TPersistent);
Begin
  If Not (Source Is TTestClass) Then Inherited
  Else
    Begin
      b := TTestClass(Source).Fb;
    End;
End;
Procedure TTestClass.LoadInstance(Var Str: TStream);
Begin
  Str.Position := 0;
  // this will work for fa and not fb.
  Str.ReadComponent(Self);
End;

Procedure TTestClass.ReallyLoadInstance(Var Str: TStream);
Begin
  Str.Position := 0;
  Assign( Str.ReadComponent(Nil));
End;
Constructor TForm1.Create(AOwner: TComponent);
Begin
  RegisterClasses([TTestClass]);
  Inherited;
  TestClass := TTestClass.Create(Self);
  Str := TmemoryStream.Create;
 End;
Destructor TForm1.Destroy;
Begin
  Str.Free;
  Inherited;
End;
Procedure TForm1.Button1Click(Sender: TObject);
Begin
  Str.Size := 0;
  TestClass.SaveInstance(Str);
End;
Procedure TForm1.Button2Click(Sender: TObject);
Begin
  If Str.Size = 0 Then Exit;
  TestClass.LoadInstance(Str);
  // guess what...only first message
End;
Procedure TForm1.Button3Click(Sender: TObject);
Begin
  If Str.Size = 0 Then Exit;
  TestClass.ReallyLoadInstance(Str);
End;

Как и в TypInfo.pas, есть случай 'tkInt64' (который, кажется, вызывает процедуру "SetProc"), не следует устанавливать опубликанные-Int64-props с использованием "Writer" (как это обычно делается с другими "общими "типы)?

Ответы [ 2 ]

7 голосов
/ 05 сентября 2011

Это потому, что вы никогда не назначаете значение свойству b. Таким образом, он имеет значение по умолчанию (ноль), и потоковая система не сохранит его в потоке. И поскольку он не находится в потоке, вы не увидите вызывающего сеттера при его чтении ...

На самом деле, поскольку вы также не присваиваете значение свойству a, то же самое должно произойти и с ним. Выглядит как ошибка (или, по крайней мере, несоответствие) в потоковой системе:

  • либо не следует сохранять / загружать свойство Integer с нулевым значением в поток,
  • или он должен сохранять / загружать их оба, поскольку в определении свойств нет спецификатора default и, следовательно, следует принимать nodefault и, следовательно, значение всегда должно быть потоковым.

Итак, подведем итоги: добавьте TestClass.b := 1; перед вызовом TestClass.SaveInstance(Str);, и вы должны увидеть вызывающий установщик при загрузке объекта обратно из потока, но вы не можете ретранслировать в потоковой системе вызов вызывающего, когда свойство имеет значение по умолчанию для типа.

1 голос
/ 05 сентября 2011

Кажется, это ошибка с Int64 в качестве свойства.

В качестве обходного пути вы можете использовать другой тип данных, например, Integer, или, если он недостаточно большой,используйте DefineProperties и TFiler.DefineProperty, TFiler.DefineBinaryProperty и т. д.

...