10.1.7 通过引用设置属性
本节讲述一个较少使用的语言功能,这节内容相当高级。如果你还没有使用Object Pascal 的经验,那么你可以跳过。但是,即使你已经熟练掌握了 Object Pascal,那么你也很可能从未听说过这项功能。
当 Object Pascal 编译器被扩展为直接支持 Windows COM 编程时,它获得了处理 "Put by Ref "属性(COM 术语)的能力,或可以接收引用而不是值的属性的能力。
注意: "Put by ref "是 Chris Bensen 在介绍该功能的博文中给它起的名字:http://chrisbensen.blogspot.com/2008/04/delphi-put-by-ref-properties.html(当时 Chris 是 Delphi 的研发工程师)。
这是通过在 setter 方法中使用 var 参数来实现的。鉴于这可能会导致相当尴尬的情况,该功能(尽管仍是语言的一部分)很大程度上被视为例外而非语言规则,这也是该功能默认不激活的原因。换句话说,要启用该功能,必须使用以下编译器指令:
{$VARPROPSETTER ON}
如果不使用该指令,以下代码将无法编译,并会出现 "E2282 Property setters cannot take var parameters"(E2282 属性设置器不能接受 var 参数)的错误:
type
TMyIntegerClass = class
private
FNumber: Integer;
function GetNumber: Integer;
procedure SetNumber(var Value: Integer);
public
property Number: Integer read GetNumber write SetNumber;
end;
该类是 VarProp 示例的一部分。现在非常奇怪的是,你可以在属性设置函数中产生副作用:
procedure TMyIntegerClass.SetNumber(var Value: Integer);
begin
Inc(Value); // Side-effect
FNumber := Value;
end;
另一个非常不寻常的情况是,你不能为属性分配一个常量值,只能分配一个变量(这应该是意料之中的,就像任何涉及通过引用传递参数的调用一样):
var
Mic: TMyIntegerClass;
N: Integer;
begin
...
Mic.Number := 10; // Error: E2036 Variable required
Mic.Number := N;
虽然这不是你经常使用的一个功能,但这是思考属性相当高级的一种方式,它允许你初始化或改变给它赋值的变量的值。这就可能会导致像这样极其奇怪的代码:
N := 10;
Mic.Number := N;
Mic.Number := N;
Show(Mic.Number.ToString);
这两个连续的、完全相同的赋值看起来相当奇怪,但它们确实导致了意外后果,将实际数字变成了 12。这可能是获得该结果的最复杂、最无意义的方法!