質問

職場では、特定のオブジェクトの多数のプロパティを、構築中または初期に設定する必要があるプロジェクトに頻繁に取り組んでいます。利便性と読みやすさのために、これらのプロパティを設定するために 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つのケースでコンパイラーを介して生成されたコードは基本的に同じであると常に考えていたため、読みやすいと思うものを常に選択することにしました。

役に立ちましたか?

解決

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

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)

他のヒント

実際には、それに対して本当に説得力のあるポイントはありません。私はファンではありませんが、それは個人的な好みです。 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 メソッドの呼び出しは、 With ステートメントの呼び出しと< code> sb :

.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

それで、あなたがそれを好きで、より読みやすいと思うならば、それを手に入れてください。しない理由はありません。

(ところで、 Tom 、私はデバッガで何が起こったのかを知りたい-私はできる」 With ステートメントに基づいてデバッガーで異常な動作を見たことを覚えていないので、どのような動作が見られたか知りたいです。)

Withの使用と、オブジェクトへの繰り返し参照の作成には違いがあります。これは微妙ですが、留意する必要があります。

WITHステートメントを使用すると、オブジェクトを参照する新しいローカル変数が作成されます。 .xxを使用する後続の参照は、そのローカル参照のプロパティへの参照です。 WITHステートメントの実行中に元の変数参照が変更された場合、WITHによって参照されるオブジェクトは変更されません。考慮:

Dim AA As AAClass = GetNextAAObject()
With AA
    AA = GetNextAAObject()

    '// Setting property of original AA instance, not later instance
    .SomeProperty = SomeValue
End With

したがって、WITHステートメントは単なる構文上の砂糖ではなく、まったく別の構造です。上記のような明示的なコードを記述することはほとんどありませんが、状況によってはこれが意図せずに発生する可能性があるため、問題に注意する必要があります。最も可能性の高い状況は、プロパティを設定することで相互接続が暗黙的に変更される可能性のあるオブジェクトのネットワークなどの構造を横断する場合です。

読みやすさのすべてです。すべての構文糖と同様に、使い古されている

IFを採用する数行にわたってオブジェクトの複数のメンバーを設定している

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

回避&quot; with&quot;を使用して他の操作を行う

50〜100行にまたがる他の多くの変数を含むWithブロックを記述すると、ブロックの先頭で宣言されたものを思い出すのが非常に難しくなります。明らかな理由から、このような厄介なコードの例は提供しません

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

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

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

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

例についての1つのメモ-「Me」が本当に必要ですか?まったく?書いてみませんか:

PropertyA = True
PropertyB = "Inactive"

?確かに「私」その場合は暗示されます...

このキーワードを大量に使用するコードには疑いがあります:多数のインスタンス変数またはプロパティの設定を容易にするために使用される場合、これはクラスが大きすぎることを示していると思われます(大きなクラスの匂い)。次のように呼び出しの長いチェーンを置き換えるために使用する場合:

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"

その後、おそらくデメテル法に違反している

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

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

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

with をJavascriptで完全に回避する理由と同じ理由で、 with のネストされた使用を回避する必要がある他の応答に同意します。プロパティが属するオブジェクトを確認します。

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

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

すべての費用でブロック付きを避けます(読みやすささえ)。 2つの理由:

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

これを説明するために、同僚が著者に質問しなければならなかった教科書の(壊れた)例があります(実際には間違っています。保護するために名前が変更されました...何でも):

  

dbcontext.Blahs
    .OrderBy(Function(currentBlah)currentBlah.LastName)
    .ThenBy(Function(currentBlah)currentBlah.FirstName)
    .Load()
  終わり

OrderByとThenByには効果なしがあります。 WithとEnd Withのみをドロップし、最初の3行の最後に行継続文字を追加するだけでコードを再フォーマットすると...(同じ教科書の 15ページ後に示すように) 。

WITHブロックを検索および破棄するのにこれ以上の理由は必要ありません。それらは、解釈済みフレームワークでのみ意味がありました。

「with」のローカルコピー(with blockでのエントリ時に作成)で作業しているため、構造体で使用する際に注意点があります。別名フィールドを設定することはできません。その場合、式とオブジェクトの参照(のコピー)を使用しない:

  

objectExpressionのデータ型は、任意のクラスまたは構造型にすることができます   または、整数などのVisual Basicの基本型です。もし   objectExpressionの結果はオブジェクト以外のものになります。   そのメンバーの値を読み取るか、メソッドを呼び出すだけで、   で使用される構造体のメンバーに値を割り当てようとするとエラー   With ... End Withステートメント。これは、次の場合に表示されるエラーと同じです   構造体を返すメソッドを呼び出し、すぐにアクセスした   関数の結果のメンバーに次のような値を割り当てました。   GetAPoint()。x =1。両方の場合の問題は、構造   呼び出しスタック上にのみ存在し、変更される方法はありません   これらの状況の構造体メンバーは、次のような場所に書き込むことができます。   プログラム内の他のコードは変更を監視できます。

     

objectExpressionは、ブロックに入るときに1回評価されます。君は   Withブロック内からobjectExpressionを再割り当てできません。

https ://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/with-end-with-statement

構造体を返す式ではなく構造体名をwithステートメントに渡すと、コンパイラはもう少し賢くなったかもしれませんが、そうではないようです

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top