在使用默认内置“组件流系统”的特定方式中,我发现如果属性的值等于默认值,则不写入它是有问题的。
让我们考虑以下方案:
您使用WriteComponent()和ReadComponent()来保存组件的特定状态。我们称这种状态为预设。该组件包含各种带有 setter 的 Real-typed 属性。
我们知道,如果一个属性等于它的默认值,那么预设将不包含该值。
所以对于我们的组件
- 我们将属性AFLoat设置为0.0
- 我们将预设保存在流中 (MyStream.WriteComponent(MyInstance))
- 我们将属性 AFLoat设置为0.101
- 我们重新加载预设(MyStream.ReadComponent(MyInstance))
最后在重新加载预设后,AFLoat仍然等于0.101,而我们期望它的值为0.0。
该错误的根源很明显,属性的默认值从未写入组件流中。所以在第2步中:该属性没有被写入,然后在第 4 步中它没有被读取......不是很烦人!
有没有办法强制将属性的默认值写入组件流中?实际上,我对 Real-typed 属性有一个自制的修复程序,但我想知道是否有一种众所周知的方法来克服潜在的问题。
我的自定义修复是在调用 ReadComponent ()之前使用 TypInfos 将 Real-typed 属性重置为 0
Procedure ResetFloatToNull(Const AnObject: TObject; Recursive: Boolean);
Var
i,j: Integer;
LList: PPropList;
Begin
j := GetPropList( AnObject, LList);
If j > 0 Then For i:= 0 To j-1 Do
Case LList^[i].PropType^.Kind Of
// floats with the object scope
tkFloat: SetFloatProp(AnObject,LList^[i].Name,0);
// floats with a subobject scope (IsSubComponent)
tkClass: If Recursive Then
ResetFloatToNull( TObject(GetOrdProp(AnObject,LList^[i])), True);
End;
FreeMem(LList);
End;
但是如果不存在其他方法,那么(隐含和次要问题):EMB 不应该放弃默认值吗?虽然它对 IDE 对象检查器(在上下文菜单中重置为继承)有点兴趣,但它完全导致了组件序列化系统中的各种烦恼......
我希望你能得到基本的问题,否则我可以添加一个小例子......
错误的小演示(在 DH 的第一个答案和评论战之后添加):
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,
classes;
type
TTestClass = class(TComponent)
private
ffloat1,ffloat2: single;
published
property float1: single read ffloat1 write ffloat1;
property float2: single read ffloat2 write ffloat2;
end;
var
str: TMemoryStream;
testclass: TTestClass;
begin
testclass := TTestClass.Create(Nil);
str := TMemoryStream.Create;
//
testclass.float1 := 0.31;
testclass.float2 := 0.32;
//
testclass.float1 := 0.0;
testclass.float2 := 0.2;
str.WriteComponent(testclass);
writeln( 'we have wrote a state when the prop 1 is equal to 0.0 and prop 2 is equal to 0.2');
//
testclass.float1 := 0.1;
testclass.float2 := 0.3;
writeln( 'then we set the prop 1 to 0.1 and prop 2 to 0.3');
writeln('');
//
writeln( 'we reload the state saved when the prop 1 was equal to 0.0 and prop 2 to 0.2 and we get:');
str.Position := 0;
str.ReadComponent(testclass);
writeln( Format( 'prop 1 equal to %.2f', [testclass.float1]));
writeln( Format( 'prop 2 equal to %.2f', [testclass.float2]));
//
writeln('');
writeln('prop 1 has not been restored because the default value 0.0 was not written');
writeln('prop 2 has been restored because a non default value was written and read');
//
ReadLn;
str.free;
testclass.free;
end.