10

usingC#と同様に、VB.NETにもキーワードがあることがわかりました。

今まで私はそれがなかったと思っていました(私は愚かです、私は知っています...)そして代わりにこのようなことをしました:

With New OleDbConnection(MyConnectionString)
   ' Do stuff
End With

usingこのようなステートメントでそれを行うことと比較して、これの意味は何ですか

Using cn as New OleDBConnection(MyConnectionString)
    With cn
        ' Do stuff with cn
    End With
End using

アップデート:

using構成が終了したときにオブジェクトを破棄するという点で、ステートメントの機能に精通していることを付け加えておきます。

ただし、私が理解している限り、With New ...コンストラクトは、オブジェクトがスコープ外になると、オブジェクトにガベージコレクションの準備ができていることをマークします。

usingだから私の質問は本当に、私がメモリをすぐに解放するのに対して、WithコンストラクトではGCがそれのように感じるときはいつでもそれが解放されるという事実だけが違いますか?それとも私はここでもっと大きなものが欠けていますか?

ベストプラクティスへの影響はありますか?私が行って、私が使用したすべてのコードを書き直す必要がありWith New MyDisposableObject() ... End WithますUsing o as New MyDisposableObject()か?

4

4 に答える 4

16

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ステートメント/ブロック

とは異なりWithUsing非常に便利で、典型的な 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。戻ってコードを再チェックし、適切な場所で使用していることを確認する必要があります。

于 2013-03-21T03:29:46.470 に答える
9

With...End With を使用すると、オブジェクトの名前を複数回指定しなくても、指定したオブジェクトに対して一連のステートメントを実行できます。

Using ブロックは、Try...Finally 構成のように動作し、Try ブロックがリソースを使用し、Finally ブロックがそれらを破棄します。

管理対象リソースは、追加のコーディングなしでガベージ コレクターによって破棄されます。UsingステートメントやWithステートメントは必要ありません。場合によっては、コードでアンマネージ リソースが必要になることがあります。それらの廃棄はお客様の責任で行ってください。Usingブロックは、コードの処理が終了したときにオブジェクトの Dispose メソッドが呼び出されること保証します。

于 2013-03-21T02:38:07.850 に答える
4

違いは、Using With...End End

Using cn as New OleDBConnection(MyConnectionString)
    With cn
        ' Do stuff with cn
    End With
End using

cn.Dispose()範囲外になると自動的に呼び出します ( End Using)。しかし、With New...End

With New OleDbConnection(MyConnectionString)
    ' Do stuff
End With

.Dispose() は明示的に呼び出されません。

また、名前付きオブジェクトを使用して、ウォッチを作成?cnし、イミディエイト ウィンドウで使用できます。名前のないオブジェクトでは、できません。

于 2013-03-21T03:27:14.993 に答える