A with
statement is a shorthand for referencing the fields of a record or the fields,
properties, and methods of an object. The syntax of a with statement is
with obj do statement
or
with obj1, ..., objn do statement
where obj is a variable reference
denoting an object or record, and statement is any simple or structured
statement. Within statement, you can refer to fields, properties, and
methods of obj using their identifiers alone without qualifiers.
For
example, given the declarations
type
TDate = record
Day: Integer;
Month: Integer;
Year: Integer;
end;
var OrderDate: TDate;
you could write the following with
statement.
with
OrderDate do
if Month = 12 then
begin
Month := 1;
Year := Year + 1;
end
else
Month := Month + 1;
This is
equivalent to
if
OrderDate.Month = 12 then
begin
OrderDate.Month := 1;
OrderDate.Year := OrderDate.Year + 1;
end
else
OrderDate.Month := OrderDate.Month + 1;
If the
interpretation of obj involves indexing arrays or dereferencing
pointers, these actions are performed once, before statement is
executed. This makes with statements efficient as well as concise. It
also means that assignments to a variable within statement cannot affect
the interpretation of obj during the current execution of the with
statement.
Each
variable reference or method name in a with statement is interpreted, if
possible, as a member of the specified object or record. If there is another
variable or method of the same name that you want to access from the with
statement, you need to prepend it with a qualifier, as in the following
example.
with
OrderDate do
begin
Year := Unit1.Year
...
end;
When
multiple objects or records appear after with, the entire statement is
treated like a series of nested with statements. Thus
with obj1, obj2, ..., objn do statement
is equivalent to
with obj1
do
with obj2 do
...
with objn do
statement
In this case, each variable reference or method name in statement is interpreted, if possible, as a member of objn; otherwise it is interpreted, if possible, as a member of objn-1; and so forth. The same rule applies to interpreting the objs themselves, so that, for instance, if objn is a member of both obj1 and obj2, it is interpreted as obj2.objn.
Structured statements: Overview
with语句是对记录中的字段或对象中的域、属性、方法等的简写。with语句的语法形式是
with obj do statement
或
with obj1, ..., objn do statement
这里的obj是表示一个对象或记录的引用,statement是任何简单语句或结构语句。在statement,中,可以通过使用相应的标识符来访问对象obj的域、属性和方法等,而不需要限定词。
例如,对于给出的声明
type
TDate = record
Day: Integer;
Month: Integer;
Year: Integer;
end;
var OrderDate: TDate;
可以写出如下的with语句:
with
OrderDate do
if Month = 12 then
begin
Month := 1;
Year := Year + 1;
end
else
Month := Month + 1;
上面的语句等价于:
if
OrderDate.Month = 12 then
begin
OrderDate.Month := 1;
OrderDate.Year := OrderDate.Year + 1;
end
else
OrderDate.Month := OrderDate.Month + 1;
如果obj的解释涉及对数组的索引或对指针的解除参照,那么在语句statement被执行之前,这些动作(索引或解除参照)会被执行一次。这使得with语句简捷高效。此外,在整个with语句执行过程中,在语句statement内部对变量的赋值不影响对obj的解释。
如果可能,with语句中的每个变量引用或方法名称都被作为指定对象或记录的成员解释。如果需要在with语句中访问另一个同名的变量或方法,那么需要为其冠以限定词,例如:
with
OrderDate do
begin
Year := Unit1.Year
...
end;
当多个对象或记录出现在with之后时,整个语句被视为一系列的嵌套with语句。如
with obj1, obj2, ..., objn do statement
等价于
with obj1
do
with obj2 do
...
with objn do
statement
这时,对于语句statement中的每个变量引用或方法名,如果可能,都作为objn的成员解释;否则,如果可能,都作为objn-1的成员解释;以此类推。对with语句所有obj的解释,也适用这同样的规则,因此,如果objn既是obj1的成员也是obj2的成员(同名),那么将被解释成obj2.objn,而不是obj1.objn。
编者注
对于出现在with语句中的变量应用或其他标识符,除了上面列举的情况之外,还可能出现标识符不属于任何with的对象(objs)但也不与所有with的对象的成员同名的情况。这时如果没有在标识符前冠以限定词,那么将依照作用域的规则来解释。例如:
var
MyVariable: string;
function
DoTest: Boolean;
var
Res: Boolean;
AForm: TForm;
Width: Integer;
begin
Res := False;
AForm := TForm.Create(Application);
with
AForm do try
...
{ 下面的MyVariable不是AForm的成员,也不需要冠以限定词
}
MyVariable := SomeStirng;
{ 下面的Width是AForm的成员,因此优先解释为AForm.Width
}
Width := 800;
...
finally
Result := Res;
Free; { 调用AForm.Free
}
end;
{ 下面语句已不在with语句中, 因此Width是指函数中声明的变量
}
Width
:= 1024;
...
end;
从另外的角度理解,可以认为,with语句超越了作用域规则,即优先于作用域规则对标识符逐一进行解释,而对那些没有成功冠以任何限定词(即找到with对象列表中合适的项)的标识符,将继续依照作用域的规则进行解释。