実際には:
procedure TBitmap32.FillRectS(const ARect: TRect; Value: TColor32);
begin
with ARect do FillRectS(Left, Top, Right, Bottom, Value);
end;
と
procedure TBitmap32.FillRectS(const ARect: TRect; Value: TColor32);
begin
FillRectS(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom, Value);
end;
まったく同じアセンブラ コードを生成します。
with
句の値が関数またはメソッドの場合、パフォーマンスが低下する可能性があります。この場合、適切な保守と高速化が必要な場合は、コンパイラが舞台裏で行うこと、つまり一時変数を作成することだけを行います。
実際には:
with MyRect do
begin
Left := 0;
Right := 0;
end;
コンパイラによって次のように擬似コードでエンコードされます。
var aRect: ^TRect;
aRect := @MyRect;
aRect^.Left := 0;
aRect^.Right := 0;
次にaRect
、単なる CPU レジスタにすることも、スタック上の真の一時変数にすることもできます。もちろん、ここでTRect
はポインターを使用しますrecord
。オブジェクトは既にポインターであるため、より直接的です。
個人的には、コード内で with を使用することもありましたが、asm が生成されるたびにほぼチェックして、本来の動作を確認しています。誰もがそれを行うことができるわけでも時間があるわけでもありません。
私は本当にそのようなコードが好きではありません:
for i := 0 to ObjList.Count-1 do
for j := 0 to ObjList[i].NestedList.Count-1 do
begin
ObjList[i].NestedList[j].Member := 'Toto';
ObjList[i].NestedList[j].Count := 10;
end;
それはまだかなり読みやすいです:
for i := 0 to ObjList.Count-1 do
for j := 0 to ObjList[i].NestedList.Count-1 do
with ObjList[i].NestedList[j] do
begin
Member := 'Toto';
Count := 10;
end;
あるいは
for i := 0 to ObjList.Count-1 do
with ObjList[i] do
for j := 0 to NestedList.Count-1 do
with NestedList[j] do
begin
Member := 'Toto';
Count := 10;
end;
しかし、内側のループが巨大な場合、ローカル変数は理にかなっています:
for i := 0 to ObjList.Count-1 do
begin
Obj := ObjList[i];
for j := 0 to Obj.NestedList.Count-1 do
begin
Nested := Obj.NestedList[j];
Nested.Member := 'Toto';
Nested.Count := 10;
end;
end;
このコードはwith
: コンパイラーが実際に舞台裏で実行します!
ちなみに、これによりデバッグが容易になります。ブレークポイントを配置してから、マウスをポイントするObj
か、Nested
直接ポイントして内部値を取得できます。