72

職場では、特定のオブジェクトの多数のプロパティを構築中またはライフタイムの早い段階で設定する必要があるプロジェクトに頻繁に取り組んでいます。利便性と読みやすさのために、Withステートメントを使用してこれらのプロパティを設定することがよくあります。見つけた

With Me.Elements
    .PropertyA = True
    .PropertyB = "Inactive"
    ' And so on for several more lines
End With

よりもはるかに良く見えます

Me.Elements.PropertyA = True
Me.Elements.PropertyB = "Inactive"
' And so on for several more lines

プロパティを設定するだけの非常に長いステートメントの場合。

Withデバッグ中に使用するといくつかの問題があることに気付きました。ただし、実際に使用を避けるべきやむを得ない理由があるかどうか疑問に思っていWithましたか? 上記の 2 つのケースでコンパイラを介して生成されたコードは基本的に同じであると常に想定してきました。

4

10 に答える 10

69

長い変数名があり、最終的に次のようになる場合:

UserHandler.GetUser.First.User.FirstName="Stefan"
UserHandler.GetUser.First.User.LastName="Karlsson"
UserHandler.GetUser.First.User.Age="39"
UserHandler.GetUser.First.User.Sex="Male"
UserHandler.GetUser.First.User.Occupation="Programmer"
UserHandler.GetUser.First.User.UserID="0"
....and so on

次に、WITH を使用して読みやすくします。

With UserHandler.GetUser.First.User
    .FirstName="Stefan"
    .LastName="Karlsson"
    .Age="39"
    .Sex="Male"
    .Occupation="Programmer"
    .UserID="0"
end with

後者の例では、最初の例よりもパフォーマンス上の利点さえあります。最初の例では、ユーザー プロパティにアクセスするたびにユーザーをフェッチし、WITH ケースではユーザーを 1 回だけフェッチするためです。

次のように、 with を使用せずにパフォーマンスを向上させることができます。

dim myuser as user =UserHandler.GetUser.First.User
myuser.FirstName="Stefan"
myuser.LastName="Karlsson"
myuser.Age="39"
myuser.Sex="Male"
myuser.Occupation="Programmer"
myuser.UserID="0"

しかし、代わりにWITHステートメントを使用します。よりきれいに見えます。

そして、これを例として取り上げたので、多くのキーワードを持つクラスについて文句を言わないでください。別の例は次のようになります: WITH RefundDialog.RefundDatagridView.SelectedRows(0)

于 2008-11-12T12:38:30.860 に答える
24

実際には、それに対して本当に説得力のあるポイントはありません。私はファンではありませんが、それは個人的な好みWithです。構造が悪いことを示唆する経験的データはありません.

.NET では、オブジェクト名の完全修飾とまったく同じコードにコンパイルされるため、このシュガーによるパフォーマンスの低下はありません。これは、次の VB .NET 2.0 クラスをコンパイルして逆アセンブルすることで確認できました。

Imports System.Text

Public Class Class1
    Public Sub Foo()
        Dim sb As New StringBuilder
        With sb
            .Append("foo")
            .Append("bar")
            .Append("zap")
        End With

        Dim sb2 As New StringBuilder
        sb2.Append("foo")
        sb2.Append("bar")
        sb2.Append("zap")
    End Sub
End Class

sb2逆アセンブルは次のとおりです。 のメソッドへの呼び出しは、 のステートメント呼び出しとAppend同じに見えることに注意してください。Withsb

.method public instance void  Foo() cil managed
{
  // Code size       91 (0x5b)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Text.StringBuilder sb,
           [1] class [mscorlib]System.Text.StringBuilder sb2,
           [2] class [mscorlib]System.Text.StringBuilder VB$t_ref$L0)
  IL_0000:  nop
  IL_0001:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.2
  IL_0009:  ldloc.2
  IL_000a:  ldstr      "foo"
  IL_000f:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0014:  pop
  IL_0015:  ldloc.2
  IL_0016:  ldstr      "bar"
  IL_001b:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0020:  pop
  IL_0021:  ldloc.2
  IL_0022:  ldstr      "zap"
  IL_0027:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_002c:  pop
  IL_002d:  ldnull
  IL_002e:  stloc.2
  IL_002f:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor()
  IL_0034:  stloc.1
  IL_0035:  ldloc.1
  IL_0036:  ldstr      "foo"
  IL_003b:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0040:  pop
  IL_0041:  ldloc.1
  IL_0042:  ldstr      "bar"
  IL_0047:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_004c:  pop
  IL_004d:  ldloc.1
  IL_004e:  ldstr      "zap"
  IL_0053:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0058:  pop
  IL_0059:  nop
  IL_005a:  ret
} // end of method Class1::Foo

したがって、気に入って読みやすくなった場合は、それを選択してください。やむを得ない理由はありません。

(ちなみに、TomWithさん、私はデバッガーで何が起こったのかを知りたいと思っています。ステートメントに基づいてデバッガーで異常な動作を見たことが思い出せないので、あなたが実際にどのような動作を見たのか知りたいです。 .)

于 2008-11-12T14:22:04.943 に答える
13

読みやすさがすべてです。すべてのシンタックス シュガーと同様に、使いすぎる可能性があります。

数行にわたってオブジェクトの複数のメンバーを設定している場合は、それを受け入れてください

With myObject
  .Property1 = arg1
  .Property2 = arg2
...

「With」で他のことをしないでください

50 ~ 100 行にまたがる With ブロックを記述し、他の多くの変数を含む場合、ブロックの先頭で宣言された内容を思い出すのが非常に難しくなる可能性があります。明らかな理由から、このような乱雑なコードの例は提供しません。

于 2012-04-05T13:09:34.267 に答える
6

コードが本当に読みやすくなる場合は、それを選択してください。読みにくくなる場合は避けてください。特に、With ステートメントのネストは避けることをお勧めします。

C# 3.0 には、オブジェクトの初期化専用の機能があります。

var x = new Whatever { PropertyA=true, PropertyB="Inactive" };

これは LINQ に必要なだけでなく、構文がコードの匂いを示さないという点でも意味があります。通常、オブジェクトに対して最初の構築を超えて多くの異なる操作を実行する場合、それらの操作はオブジェクト自体で単一の操作としてカプセル化する必要があります。

あなたの例についての注意点-「私」は本当に必要ですか?単に書いてみませんか:

PropertyA = True
PropertyB = "Inactive"

? その場合、確かに「私」が暗示されています...

于 2008-11-12T12:24:01.810 に答える
5
于 2008-11-12T12:55:33.197 に答える
3

「with」は基本的に Smalltalk の「カスケード」です。これは Kent Beck の Smalltalk Best Practice Patterns book のパターンです。

パターンの要約: オブジェクトに送信されるメッセージをグループ化することが理にかなっている場合に使用します。たまたま同じオブジェクトに送信されたいくつかのメッセージである場合は、使用しないでください。

于 2009-11-12T15:31:10.273 に答える
3

私はVB.NETを使用していません(以前はプレーンなVBを使用していました)が...

先頭のドットは必須ですか? もしそうなら、私は問題を見ていません。Javascript では、使用の結果with、オブジェクトのプロパティがプレーンな変数と同じように見えます。これは、プロパティまたは変数にアクセスしいるかどうかがわからないため、非常に危険ですwith。避けるべきもの。

見た目が簡単なだけでなく、オブジェクトのプロパティに繰り返しアクセスする場合、オブジェクトがすべてのプロパティに対して 1 回ではなく、メソッド チェーンを介して 1 回だけフェッチされるため、高速になる可能性があります。

Javascript で完全にwith避けるべき理由と同じ理由で、 のネストされた使用を避けるべきであるという他の回答に同意します。with

于 2008-11-12T14:09:48.260 に答える
2

WITH ブロックは絶対に避けてください (読みやすさも含めて)。2 つの理由:

  1. With...End With に関する Microsoftのドキュメントには、状況によっては、スタック上にデータのコピーが作成されるため、行った変更はすべて破棄されることが記載されています。
  2. LINQ クエリに使用する場合、ラムダの結果は連鎖しないため、各中間句の結果は破棄されます。

これを説明するために、同僚が著者に尋ねなければならなかったテキストブックからの(壊れた)例があります(これは実際には正しくありません。保護するために名前が変更されています...何でも):

With dbcontext.Blahs
.OrderBy(Function(currentBlah) currentBlah.LastName)
.ThenBy(Function(currentBlah) currentBlah.FirstName)
.Load()
End With

OrderBy と ThenBy はまったく効果がありません。With と End With を削除し、最初の 3 行の最後に行継続文字を追加するだけでコードを再フォーマットする場合... 動作します (同じ教科書の15 ページで示されているように)。

WITH ブロックを検索して破棄する理由はもう必要ありません。それらは、解釈されたフレームワークでのみ意味を持ちました。

于 2015-09-24T15:45:37.427 に答える