Withステートメント/ブロック
ただし、私が理解している限りでは、 With New ... コンストラクトは、オブジェクトがスコープ外になったときにオブジェクトをガベージ コレクションの準備ができているとマークします。
これは真実でもあり、真実でもありません。すべてのオブジェクトが、範囲外になったときにガベージ コレクションの準備ができていると「マーク」される (純粋主義者はこの用語に疑問を呈するかもしれませんが、詳細は関係ありません)という意味で、これは真実です。Withしかし、その意味では、この動作に関してキーワードについて特別なことは何もないので、それは完全に真実でもありません. オブジェクトが範囲外になると、ガベージ コレクションの対象になります。限目。これはメソッド レベルのスコープにも当てはまり、ブロック レベルのスコープにも当てはまります (例: 、、Withなど)。ForUsing
しかし、それがあなたが使用する理由ではありませんWith。その理由は、深くネストされたオブジェクトに複数のプロパティを順番に設定できるからです。つまり、一連のプロパティを設定したいオブジェクトがあり、次の方法でアクセスするとしますMyClass.MemberClass.AnotherMemberClass.Items(0)。これらのドットがすべて見えますか?プロパティを設定するたびにまったく同じオブジェクトにアクセスするために、一連のドットを何度も処理しなければならないコードを記述すると、(理論的には) 非効率になる可能性があります。C または C++ (またはポインターを持つ他の言語) について何か知っている場合は、これらのドットのそれぞれがポインター逆参照を暗示していると考えることができます。Withステートメントは基本的に、そのすべての間接処理を 1 回だけ実行し、結果のオブジェクトを一時変数に格納します。、および一時変数に格納されているそのオブジェクトに直接プロパティを設定できるようにします。
おそらく、いくつかのコードが物事をより明確にするのに役立つでしょう。ドットが表示されるたびに、速度が遅い可能性があると考えてください。
次のコードから始めて、深くネストされたItemsコレクションからオブジェクト 1 を取得し、それに複数のプロパティを設定するとします。毎回まったく同じオブジェクトであるにもかかわらず、何回オブジェクトを取得しなければならないことがわかりますか?
MyClass.MemberClass.AnotherMemberClass.Items(0).Color = Blue
MyClass.MemberClass.AnotherMemberClass.Items(0).Width = 10
MyClass.MemberClass.AnotherMemberClass.Items(0).Height = 5
MyClass.MemberClass.AnotherMemberClass.Items(0).Shape = Circle
MyClass.MemberClass.AnotherMemberClass.Items(0).Texture = Shiny
MyClass.MemberClass.AnotherMemberClass.Items(0).Volume = Loud
With次に、ブロックを使用するようにそのコードを変更します。
With MyClass.MemberClass.AnotherMemberClass.Items(0)
.Color = Blue
.Width = 10
.Height = 5
.Shape = Circle
.Texture = Shiny
.Volume = Loud
End With
ただし、ここでの効果は次のコードと同じです。
Dim tempObj As MyObject = MyClass.MemberClass.AnotherMemberClass.Items(0)
tempObj.Color = Blue
tempObj.Width = 10
tempObj.Height = 5
tempObj.Shape = Circle
tempObj.Texture = Shiny
tempObj.Volume = Loud
確かに、新しいスコープを導入しないためtempObj、より高いレベルのスコープが終了するまでスコープ外に出ることはありません (したがって、ガベージ コレクションの対象にはなりません) が、それはほとんど問題になりません。パフォーマンスの向上 (ある場合) は、後者の 2 つのコード スニペットの両方に適用されます。
現在、ブロックを使用することの真Withのメリットはパフォーマンスではなく、読みやすさです。With、パフォーマンスの改善の可能性、文体の提案などの詳細については、この質問への回答を参照してください。
With New?
Newステートメントにキーワードを追加すると、With先ほど説明した (オブジェクトを保持するローカル一時変数を作成する) のとまったく同じ効果がありますが、ほとんど無意味です。でオブジェクトを作成する必要がある場合はNew、それを保持する変数を宣言することもできます。おそらく、後でそのオブジェクトを別のメソッドに渡すなど、何かをする必要があるでしょうが、それをWithブロック内で行うことはできません。
の唯一の目的はWith New、明示的な変数宣言を回避できるようにすることであり、代わりにコンパイラーに暗黙的に宣言させることです。私をクレイジーと呼んでください。しかし、これには何の利点もありません。
実際、正直なところ、この構文を使用する実際のコードを見たことがないと言えます。私が Google で見つけられる唯一のものは、このようなナンセンスです(Callとにかく、はるかに優れた代替手段です)。
Usingステートメント/ブロック
とは異なりWith、Usingは非常に便利で、典型的な VB.NET コードで頻繁に使用されます。ただし、その適用範囲は非常に限られています。型がインターフェイス パターンを実装しているオブジェクトでのみ機能します。これは、管理されていないリソースを解放するために、処理が終了したときにいつでも呼び出す必要IDisposableがあるメソッドがオブジェクトにあるかどうかを確認することで確認できます。Dispose
ところで、これは、オブジェクトにDisposeメソッドがある場合は常に従うべき規則です。オブジェクトを使い終わったら、必ずメソッドを呼び出す必要があります。そうしない場合、必ずしも世界の終わりではありません — ガベージ コレクターがあなたのベーコンを救うかもしれません — しかし、それは文書化された契約の一部であり、Disposeそれを提供する各オブジェクトを呼び出すことは常にあなたの側で良い習慣です。
ブロックに実装されていないオブジェクトの作成をラップしようとすると、コンパイラが吠えてエラーを生成します。その機能は本質的に/ブロックと同等であるため、他のタイプには意味がありません。IDisposableUsingTryFinally
Try
' [1: Create/acquire the object]
Dim g As Graphics = myForm.CreateGraphics()
' [2: Use the object]
g.DrawLine(Pens.Blue, 10, 10, 100, 100)
' ... etc.
End Try
Finally
' [3: Ensure that the object gets disposed, no matter what!]
g.Dispose()
End Finally
しかし、これは見苦しく、ネストを開始するとかなり扱いにくくなります (破棄するPen必要のあるオブジェクトを作成した場合のように)。代わりにUsing、同じ効果を持つを使用します。
' [1: Create/acquire the object]
Using g As Graphics = myForm.CreateGraphics()
' [2: Use the object]
g.DrawLine(Pens.Blue, 10, 10, 100, 100)
' ...etc.
End Using ' [3: Ensure that the object gets disposed, no matter what!]
このUsingステートメントは、(Newキーワードを使用するか、または のようなメソッドを呼び出してCreateGraphics)最初に取得するオブジェクトと、既に作成したオブジェクトの両方で機能します。どちらの場合もDispose、ブロック内のどこかで例外がスローされた場合でも、メソッドが呼び出されることが保証されます。これにより、オブジェクトのアンマネージ リソースが正しく破棄されます。
ステートメントを知らずに VB.NET でコードを書いていることに少し恐怖を覚えます。Usingすべてのオブジェクトの作成に使用するわけではありませんが、実装するオブジェクトを扱う場合は非常に重要ですIDisposable。戻ってコードを再チェックし、適切な場所で使用していることを確認する必要があります。