34

私は Delphi のwithキーワードについて悪いことを読んでいますが、私の意見では、それを使いすぎなければ。コードをシンプルに見せることができます。

多くの場合、すべての TClientDataSet と TField を TDataModule に入れます。私のフォームでは、このようなコードがありました

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  with LongNameDataModule do
  begin
     LongNameTable1.Insert;
     LongNameTable1_Field1.Value := "some value";
     LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
     LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
     LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
     LongNameTable1.Post;
  end
end;

withキーワードがなければ、このようなコードを書かなければなりません

    procedure TMyForm.AddButtonClick(Sender: TObject);
    begin            
      LongNameDataModule.LongNameTable1.Insert;
      LongNameDataModule.LongNameTable1_LongNameField1.Value := "some value";

      LongNameDataModule.LongNameTable1_LongNameField2.Value :=
               LongNameDataModule.LongNameTable2_LongNameField1.Value;

      LongNameDataModule.LongNameTable1_LongNameField3.Value :=
               LongNameDataModule.LongNameTable3_LongNameField1.Value;

      LongNameDataModule.LongNameTable1_LongNameField4.Value :=
               LongNameDataModule.LongNameTable4_LongNameField1.Value;

      LongNameDataModule.LongNameTable1.Post;
    end;

withキーワードを使った方が読みやすいと思います。

withキーワードの使用を避けるべきですか?

4

14 に答える 14

61

「with A、B、C、D」のような病的状態以外の with の最大の危険は、コードが予告なしに黙って意味を変更できることです。次の例を検討してください。

with TFoo.Create
try
  Bar := Baz;
  DoSomething();
finally
  Free;
end;

Bar が TFoo のプロパティであり、Baz がこのコードを持つメソッドを含む型のプロパティであることを認識して、このコードを記述します。

2 年後、善意の開発者が Baz プロパティを TFoo に追加します。あなたのコードは静かに意味を変えました。コンパイラは文句を言いませんが、コードは壊れています。

于 2009-02-05T13:46:07.320 に答える
32

withキーワードは、コードを読みやすくするための優れた機能ですが、いくつかの落とし穴があります。

デバッグ:

次のようなコードを使用する場合:

with TMyClass.Create do
try
  Add('foo');
finally
  Free;
end;

このクラスのプロパティを検査する方法はないため、常に変数を宣言し、withキーワードを使用してください。

インターフェース:

with句でインターフェイスを作成すると、メソッドの最後まで存続します。

procedure MemoryHog;
begin
  with GetInterfaceThatTakes50MBOfMemory do
    Whatever;
  ShowMessage('I''m still using 50MB of memory!');
end;

明瞭さ

スコープ内に既に存在するプロパティまたはメソッド名を持つクラスをwith句で使用すると、簡単にだまされる可能性があります。

with TMyForm.Create do
  Width := Width + 2; //which width in this with is width?

もちろん、名前が重複している場合は、with ステートメント (TMyForm) で宣言されているクラスのプロパティとメソッドを使用しています。

于 2009-02-05T09:01:47.677 に答える
23

ステートメントにはそのwith場所がありますが、使いすぎるとあいまいなコードになる可能性があることに同意する必要があります。経験則として、with ステートメントを追加した後、コードが「より」読みやすく、保守しやすいようにすることをお勧めします。ステートメントを追加した後にコードを説明するためにコメントを追加する必要があると思われる場合は、おそらく悪い考えです。あなたの例のようにコードが読みやすい場合は、それを使用してください。

ところで:これは、モーダル ウィンドウを表示するための Delphi での私のお気に入りのパターンの 1 つでした。

with TForm.Create(nil) do
try
  ShowModal;
finally
  Free;
end
于 2009-02-05T04:02:03.583 に答える
15

私はwith-statementを完全に禁止する傾向があります。前に述べたように、それは物事を複雑にする可能性があり、私の経験ではそうなるでしょう。多くの場合、デバッガーはwithsのために値を評価する必要があり、多くの場合、コードを読みにくくするネストされたwithsを見つけます。

ブライアンのコードは読みやすくて素敵なようですが、送信者を直接型キャストするだけでコードが短くなり、有効にするコンポーネントに関する疑問をすべて取り除くことができます。

TAction(Sender).Enabled := Something;

あなたが多くのことをタイプすることを心配しているなら、私は長い名前のオブジェクトへの一時的な参照をするために前払いします:

var
  t: TTable;
begin
  t := theLongNamedDataModule.WithItsLongNamedTable;
  t.FieldByName(' ');
end;

しかし、なぜタイピングがあなたを悩ませるべきなのか私にはわかりません。私たちは最初にタイピスト、次にプログラマーであり、コード補完、コピー&ペースト、およびキー記録は、より効果的なタイピストになるのに役立ちます。

更新:with-statementsに関する小さなセクションがある長い記事に出くわしました:彼はキーワードを持っています。この言語で最も恐ろしい、危険な、自分の足を吹き飛ばす機能。:-)

于 2009-02-05T08:40:30.917 に答える
8

私が最初にパスカル プログラミングを (TurboPascal で!) 始めたとき、学びながら、WITH は素晴らしいものに思えました。おっしゃる通り、面倒なタイピングへの答えであり、長いレコードに最適です。Delphi が登場して以来、私はそれを削除し、他の人にそれを削除するように勧めてきました -レジで Verity によってきちんとまとめられて います 読みやすさの低下とは別に、私がそれを避ける主な理由が 2 つあります。

  1. クラスを使用する場合、とにかくそれは必要ありません-レコードだけがそれから恩恵を受けるように見えます。
  2. デバッガーを使用して、Ctrl-Enter を使用してコードを宣言までたどっても機能しません。

とはいえ、読みやすくするために、私はまだ構文を使用しています。

procedure ActionOnUpdate( Sender : TObject )
begin
  With Sender as TAction do
    Enabled := Something
end;

私はより良い構造を見たことがありません。

于 2009-02-05T06:51:45.053 に答える
6

Vegarが述べたように、それは同じようにきちんとしていて、はるかに読みやすく、デバッグが簡単で、一時的な参照を使用するためにステルスの問題が発生する可能性が低くなります。

これまでのところ、で使用する必要性を見つけたことはありませんマインドベンディングダブルを頻繁に使用するプロジェクトを引き継ぐまで、私はそれについて曖昧でした。元の開発者が最初のwithまたはsecondのアイテムを参照することを意図していたかどうか、そのあいまいな参照がwith-slipまたは不器用なコードであるかどうか、それをデバッグしようとする苦痛、およびこれらを使用するクラスを拡張または変更することのノックオン効果を質問する忌まわしきは、誰にとっても時間の価値がありません。

明示的なコードは単により読みやすくなります。このようにして、ケーキを食べて楽しむことができます。

procedure TMyForm.AddButtonClick(Sender: TObject);
var
  dm: TLongNameDataModuleType
begin  
  dm:=LongNameDataModule;

  dm.LongNameTable1.Insert;
  dm.LongNameTable1_Field1.Value := "some value";
  dm.LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
  dm.LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
  dm.LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
  dm.LongNameTable1.Post;
end;
于 2012-01-17T09:50:37.147 に答える
6

ボタンクリック内のデータモジュールアクセスのあなたの例は、私の意見では不十分な例です。このコードをデータ モジュール内の必要な場所に移動すると、WITH の必要性がなくなります。次に、OnClick は LongNameDataModule.InsertStuff を呼び出すだけで、必要なものはありません。

With は貧弱なデバイスです。コードを調べて、なぜそれが必要なのかを確認する必要があります。あなたはおそらく何か間違ったことをしたか、もっと良い方法でそれを行うことができました.

于 2009-02-05T09:12:46.000 に答える
5

あなたの質問は、「ハンマーが常に解決策であるとは限らない」という優れた例です。

この場合、'with' は解決策ではありません。このビジネス ロジックをフォームからデータ モジュールに移動する必要があります。そうしないと、 mghie (Michael Hieke) が既にコメントしたように、Demeter の法則に違反します。

あなたの例は単なる説明にすぎないかもしれませんが、プロジェクトで実際にそのようなコードを使用している場合は、代わりに次のことを行う必要があります。

procedure TLongNameDataModule.AddToLongNameTable1(const NewField1Value: string);
begin  
  LongNameTable1.Insert;
  LongNameTable1_Field1.Value := NewField1Value;
  LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
  LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
  LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
  LongNameTable1.Post;
end;

そして、次のようにフォームから呼び出します。

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  LongNameDataModule.AddToLongNameTable1('some value');
end;

これにより、 with ステートメントが効果的に取り除かれ、同時にコードがより保守しやすくなります。

もちろん、Delphi 文字列を一重引用符で囲むと、コンパイルにも役立ちます ;-)

于 2009-04-29T07:41:30.643 に答える
3

「with」の主な問題は、そのスコープがどこで終了するかわからないことと、複数の with ステートメントが重複する可能性があることです。

コードが読める限り、使用を避けるべきではないと思います。

読みやすくする (そして長いコードでの混乱を少なくする) ための提案の 1 つは、codegear が wi​​thでエイリアスを許可するオプションを追加し、おそらく複数の with を 1 つに許可することでした。

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  with LongNameDataModule as dm, dm.LongNameTable1 as t1, dm.LongNameTable2 as t2 do
  begin
    t1.Insert;
    t1.FieldByName('Field1').AsString := 'some value';
    t1.FieldByName('Field2').AsString := t2.FieldByName('Field2').AsString;
    t1.Post;
    dm.Connection.Commit;
  end
end;
于 2009-02-05T04:07:29.610 に答える
2

with ステートメントが悪い理由については、ここに多くの優れた回答があるので、それらを繰り返さないようにします。私は何年も with ステートメントを使用してきましたが、非常に敬遠し始めています。これは部分的には、スコープを決定するのが難しいためですが、私は最近リファクタリングに取り掛かり始めており、with ステートメントでは自動リファクタリングが機能しません。自動リファクタリングは素晴らしいものです。

また、少し前にwithステートメントが悪い理由についてビデオを作成しました。これは私の最高の作品の1つではありませんが、ここにあります

于 2009-02-05T22:10:48.643 に答える
-1

現在の With ステートメントは「危険」ですが、大幅に改善できます。

  With TForm1.Create (Nil) Do  // New TForm1 instance
    Try
      LogForm (");  // That same instance as parameter to an outer method
      "ShowModal;  // Instance.ShowModal
    Finally
      "Free;  // Instance.Free
    End;

私の提案は次のとおりです。

  1. With ヘッダーごとに 1 つのオブジェクト/レコードのみ。
  2. With のネストは許可されていません。
  3. " を使用してオブジェクト/レコードを示します (二重引用符は同上マークに似ています: http://en.wikipedia.org/wiki/Ditto_mark )。
于 2014-03-15T18:52:15.397 に答える