22

多くのプログラマー、特に Delphi プログラマーは「with」の使用を軽蔑していると聞きました。

プログラムの実行が速くなり (親オブジェクトへの参照が 1 つだけ)、賢明に使用すればコードが読みやすくなると思いました (コードは 12 行未満で、ネストはありません)。

次に例を示します。

procedure TBitmap32.FillRectS(const ARect: TRect; Value: TColor32);
begin
  with ARect do FillRectS(Left, Top, Right, Bottom, Value);
end;

を使うのが好きwithです。私がどうかしましたか、まずいことでもありましたか?

4

16 に答える 16

33

with を使用する際の煩わしさの 1 つは、デバッガーがそれを処理できないことです。そのため、デバッグがより困難になります。

より大きな問題は、コードが読みにくいことです。特にwithステートメントが少し長い場合。

procedure TMyForm.ButtonClick(...)
begin
  with OtherForm do begin
    Left := 10;
    Top := 20;
    CallThisFunction;
  end;
end;

どのフォームの CallThisFunction が呼び出されますか? Self (TMyForm) または OtherForm? OtherForm に CallThisFunction メソッドがあるかどうかを確認しないとわかりません。

そして最大の問題は、知らず知らずのうちに簡単にバグを作ってしまうことです。TMyForm と OtherForm の両方に CallThisFunction があるが、それが非公開の場合はどうなるでしょうか。OtherForm.CallThisFunction が呼び出されることを期待/希望するかもしれませんが、実際にはそうではありません。with を使用していない場合、コンパイラは警告を表示していましたが、現在は警告を表示していません。

with で複数のオブジェクトを使用すると、問題が倍増します。http://blog.marcocantu.com/blog/with_harmful.htmlを参照してください。

于 2008-09-16T11:44:41.137 に答える
12

.ここでは、あいまいさを避けるために with ブロック内のメンバーの前に a を付ける必要があるため、この場合は VB 構文を好みます。

With obj
    .Left = 10
    .Submit()
End With

しかし、実際には、一般的には何も問題はありませんwith

于 2008-09-16T11:44:34.697 に答える
12

withステートメントが次のように拡張されると素晴らしいでしょう。

with x := ARect do
begin
  x.Left := 0;
  x.Rigth := 0;
  ...
end;

変数「x」を宣言する必要はありません。コンパイラによって作成されます。書くのは簡単で、どの関数が使用されているか混乱することはありません。

于 2010-03-05T06:38:22.387 に答える
8

「with」によってコードの実行が速くなる可能性は低く、コンパイラーが同じ実行可能コードにコンパイルする可能性が高くなります。

人々が「with」を好まない主な理由は、名前空間のスコープと優先順位について混乱を招く可能性があるためです。

これが実際の問題である場合と、これが問題ではない場合があります(非問題の場合は、質問で「賢明に使用された」と説明されているとおりです)。

混乱が生じる可能性があるため、一部の開発者は、そのような混乱がない場合でも、「with」を完全に使用しないことを選択します。これは独断的に見えるかもしれませんが、コードが変更されて成長するにつれて、「with」を混乱させる程度にコードが変更された後でも「with」の使用が残る可能性があるため、そもそもその使い方を紹介します。

于 2008-09-16T11:53:33.223 に答える
7

実際には:

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直接ポイントして内部値を取得できます。

于 2012-09-04T16:14:17.050 に答える
3

これは主にメンテナンスの問題です。

WITHの概念は、言語の観点からは合理的な意味があり、コードを適切に使用すると、より小さく、より明確にコードを保持するという議論にはある程度の妥当性があります。ただし、問題は、ほとんどの商用コードがその存続期間にわたって複数の異なる人々によって維持されることであり、記述されたときに小さくて簡単に解析できる構造として始まるものは、WITHのスコープがない扱いにくい大きな構造に時間の経過とともに簡単に変化する可能性がありますメンテナが簡単に解析できます。これは当然バグを発生させる傾向があり、バグを見つけるのは困難です。

たとえば、WITHブロック内にラップされた3行または4行のコードを含む小さな関数fooがある場合、実際には問題はありません。ただし、数年後、この関数は、数人のプログラマーの下で、まだWITH内にラップされた40行または50行のコードに拡張された可能性があります。これは現在もろく、バグが発生する可能性があります。特に、メンテナが追加の埋め込みWITHブロックを導入する場合はそうです。

WITHには他の利点はありません-コードはまったく同じように解析され、同じ速度で実行される必要があります(3Dレンダリングに使用されるタイトなループ内でD6でいくつかの実験を行いましたが、違いは見つかりませんでした)。デバッガーがそれを処理できないことも問題ですが、しばらく前に修正されているはずであり、何らかの利点がある場合は無視する価値があります。残念ながらありません。

于 2010-03-04T20:47:10.177 に答える
3

この議論はJavascriptでもよく起こります。

基本的に、この With 構文では、呼び出している Left/Top/etc プロパティ/メソッドを一目で判断するのが非常に難しくなります。Left というローカル変数とプロパティを使用できます (私がDelphi を実行しました。名前が間違っていたらごめんなさい) Left と呼ばれ、おそらく Left と呼ばれる関数でさえあります。ARect 構造にあまり精通していないコードを読んでいる人は、非常に混乱する可能性があります。

于 2008-09-16T11:40:48.387 に答える
3

タイピングで節約できるものは、読みやすさを失います。多くのデバッガーは、何を参照しているのかわからないため、デバッグはより困難になります。プログラムの実行が速くなるわけではありません。

with ステートメント内のコードを、参照しているオブジェクトのメソッドにすることを検討してください。

于 2008-09-16T11:48:42.110 に答える
2

ステートメントと組み合わせることができるので、最終的には

with Object1, Object2, Object3 do
begin
  //... Confusing statements here
end

withそして、デバッガーが混乱していると思われる場合は、ブロックで何が起こっているのかを誰がどのように判断できるかわかりません

于 2010-06-27T09:37:30.833 に答える
2

デバッグが面倒になるので好きではありません。変数などの値は、マウスでホバーしただけでは読み取れません。

于 2008-09-16T11:38:27.173 に答える
2

シンプルに保ち、あいまいさを避ける限り、問題はありません。

私が知る限り、それは何もスピードアップしません - それは純粋に構文糖衣です.

于 2008-09-16T11:41:43.780 に答える
2

職場では、既存の Win 32 コード ベースから Withs を削除することを推奨しています。これは、Withs を使用するコードを維持するために余分な労力が必要になるためです。以前のジョブで、BusinessComponent というローカル変数が、同じタイプの BusinessComponent プロパティを発行したオブジェクトの With begin ブロック内にあることでマスクされていたというバグをいくつか発見しました。コンパイラは公開されたプロパティを使用することを選択し、ローカル変数を使用することを意図したコードがクラッシュしました。

私は次のようなコードを見てきました

a,b,c,d do {ただし、それらははるかに長い名前であり、ここでは短縮されています) begin i := xyz;
終わり;

xyz がどこから来たのかを突き止めようとするのは本当に大変なことです。それが c だったら、もっと早く次のように書きます。

i := c.xyz;

これを理解するのはかなり簡単だと思いますが、最初に with を使用した 800 行の長さの関数では理解できません!

于 2008-09-16T11:49:20.160 に答える
1
...より速く実行します...

必ずしもそうとは限りません-コンパイラ/インタプリタは、一般的に、コードの最適化に優れています。

「うん!」と言わせてくれると思います。それは怠惰だからです-私がコード(特に他の誰かの)を読んでいるとき、私は明示的なコードを見るのが好きです。したがって、Javaでは「field」の代わりに「this.field」と書くこともできます。

于 2008-09-16T11:59:50.743 に答える
1

無能または邪悪なプログラマーが読めないコードを書くことを許してしまいます。したがって、あなたが無能でも悪人でもない場合にのみ、この機能を使用してください。

于 2008-09-16T11:46:28.683 に答える
-1

最近、Delphiのコーディング標準で禁止しました。

長所はしばしば短所を上回っていました。

それは、その誤用のためにバグが導入されていたということです。これらは、コードの記述または実行にかかる時間の節約を正当化するものではありませんでした。

はい、withを使用すると、コードの実行が(わずかに)速くなります。

以下では、fooは1回だけ評価されます。

with foo do
begin
  bar := 1;
  bin := x;
  box := 'abc';
end

しかし、ここでは3回評価されます。

foo.bar := 1;
foo.bin := x;
foo.box := 'abc';
于 2008-09-16T11:57:27.003 に答える
-1

Delphi 2005の場合、with-doステートメントにハードエラーが存在します-評価ポインターが失われ、ポインターを上にして再処理します。オブジェクトタイプを直接使用するのではなく、ローカル変数を使用する必要があります。

于 2010-07-27T09:05:22.730 に答える