With... End With vs Using in VB.NET
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15538438/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
With... End With vs Using in VB.NET
提问by yu_ominae
I just found out that like C#, VB.NET also has the usingkeyword.
我刚刚发现和 C# 一样,VB.NET 也有using关键字。
Until now I thought it didn't have it (stupid of me, I know...) and did stuff like this instead:
直到现在我认为它没有它(愚蠢的我,我知道......)并做了这样的事情:
With New OleDbConnection(MyConnectionString)
' Do stuff
End With
What are the implications of this compared to doing it with a usingstatement like this
与使用这样的using语句相比,这样做的意义是什么
Using cn as New OleDBConnection(MyConnectionString)
With cn
' Do stuff with cn
End With
End using
UPDATE:
更新:
I should add that I am familiar with what the usingstatement does in that it disposes of the object when the construct is exited.
我应该补充一点,我熟悉该using语句的作用,因为它在构造退出时处理对象。
However, as far as I understand the With New ...construct will have the object mark the object as ready for garbage collection when it goes out of scope.
但是,据我了解,With New ...当对象超出范围时,该构造会将对象标记为准备好进行垃圾收集。
So my question really is, is the only difference the fact that with usingI will release the memory right away, whereas with the Withconstruct it will be released whenever the GC feels like it? Or am I missing something bigger here?
所以我的问题真的是,唯一的区别是using我会立即释放内存,而对于With构造,只要 GC 感觉它就会被释放?还是我在这里错过了更大的东西?
Are there any best practice implications? Should I go and rewrite all the code with I used With New MyDisposableObject() ... End Withas Using o as New MyDisposableObject()?
是否有任何最佳实践影响?我应该使用With New MyDisposableObject() ... End Withas重写所有代码Using o as New MyDisposableObject()吗?
采纳答案by Jacob Seleznev
By using With...End With, you can perform a series of statements on a specified object without specifying the name of the object multiple times.
A Using block behaves like a Try...Finally construction in which the Try block uses the resources and the Finally block disposes of them.
通过使用 With...End With,您可以对指定的对象执行一系列语句,而无需多次指定对象的名称。
Using 块的行为类似于 Try...Finally 构造,其中 Try 块使用资源,而 finally 块处理它们。
Managed resources are disposed by the garbage collector without any extra coding on your part. You do not need Usingor Withstatements. Sometimes your code requires unmanaged resources. You are responsible for their disposal. A Usingblock guarantees that the Disposemethod on the object is called when your code is finished with them.
托管资源由垃圾收集器处理,您无需进行任何额外编码。您不需要Using或With语句。有时您的代码需要非托管资源。您有责任处理它们。一个使用块保证了处置,当你的代码与他们完成的对象上调用方法。
回答by Cody Gray
WithStatements/Blocks
With语句/块
However, as far as I understand the With New ... construct will have the object mark the object as ready for garbage collection when it goes out of scope.
但是,据我所知, With New ... 构造将使对象在超出范围时将对象标记为准备好进行垃圾收集。
This is both true and not true. It is true in the sense that allobjects are "marked" (purists might quibble with this terminology, but the details are not relevant) as ready for garbage collection when they go out of scope. But then in that sense, it is also not entirely true, as there's nothing special about the Withkeyword with respect to this behavior. When an object goes out of scope, it is eligible for garbage collection. Period. That's true for method-level scope and it's true for block-level scope (e.g., With, For, Using, etc.).
这既真实又不真实。从某种意义上说,所有对象都被“标记”(纯粹主义者可能会用这个术语狡辩,但细节无关紧要)在它们超出范围时准备好进行垃圾收集是正确的。但从这个意义上说,它也不完全正确,因为With与此行为相关的关键字没有什么特别之处。当一个对象超出范围时,它就有资格进行垃圾回收。时期。对于方法级作用域和块级作用域(例如With,For、Using、 等)都是如此。
But that's not why you use With. The reason is that it allows you to set multiple properties in sequence on a deeply-nested object. In other words, assume you have an object on which you want to set a bunch of properties, and you access it this way: MyClass.MemberClass.AnotherMemberClass.Items(0). See all those dots? It can (theoretically) become inefficient to write code that has to work through that series of dots over and over to access the exact same object each time you set a property on it. If you know anything about C or C++ (or any other language that has pointers), you can think of each of those dots as implying a pointer dereference. The Withstatement basically goes through all of that indirection only once, storing the resulting object in a temporary variable, and allowing you to set properties directly on that object stored in the temporary variable.
但这不是您使用With. 原因是它允许您在深度嵌套的对象上按顺序设置多个属性。换句话说,假设您有一个要在其上设置一系列属性的对象,并且您可以通过以下方式访问它:MyClass.MemberClass.AnotherMemberClass.Items(0). 看到所有这些点了吗?每次在其上设置属性时,编写代码必须一遍又一遍地通过这一系列点来访问完全相同的对象,这可能会(理论上)变得低效。如果您对 C 或 C++(或任何其他具有指针的语言)有所了解,您可以将这些点中的每一个视为暗示指针取消引用。该With语句基本上只遍历所有间接访问一次,将结果对象存储在一个临时变量中,并允许您直接在存储在临时变量中的对象上设置属性。
Perhaps some code would help make things clearer. Whenever you see a dot, think might be slow!
也许一些代码可以帮助使事情更清晰。每当你看到一个点时,想想可能会很慢!
Assume that you start out with the following code, retrieving object 1 from a deeply-nested Itemscollection and setting multiple properties on it. See how many times we have to retrieve the object, even though it's exactly the same object every time?
假设您从以下代码开始,从深度嵌套的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
Now we modify that code to use a Withblock:
现在我们修改该代码以使用With块:
With MyClass.MemberClass.AnotherMemberClass.Items(0)
.Color = Blue
.Width = 10
.Height = 5
.Shape = Circle
.Texture = Shiny
.Volume = Loud
End With
The effect here, however, is identical to the following code:
但是,这里的效果与以下代码相同:
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
Granted, you don't introduce a new scope, so tempObjwon't go out of scope (and therefore be eligible for garbage collection) until the higher level scope ends, but that's hardly ever a relevant concern. The performance gain (if any) attaches to both of the latter two code snippets.
当然,您不会引入新的范围,因此tempObj在更高级别的范围结束之前不会超出范围(因此有资格进行垃圾收集),但这几乎不是相关问题。性能增益(如果有)附加到后两个代码片段。
The realwin of using Withblocks nowadays is not performance, but readability. For more thoughts on With, possible performance improvements, stylistic suggestions, and so on, see the answers to this question.
现在使用块的真正优势With不是性能,而是可读性。有关With可能的性能改进、风格建议等的更多想法,请参阅此问题的答案。
With New?
With New?
Adding the Newkeyword to a Withstatement has exactly the same effect that we just discussed (creating a local temporary variable to hold the object), except that it's almost an entirely pointless one. If you need to create an object with New, you might as well declare a variable to hold it. You're probably going to need to dosomething with that object later, like pass it to another method, and you can't do that in a Withblock.
将New关键字添加到With语句与我们刚刚讨论的效果完全相同(创建一个局部临时变量来保存对象),只是它几乎完全没有意义。如果你需要用 来创建一个对象New,你不妨声明一个变量来保存它。稍后您可能需要对该对象执行某些操作,例如将其传递给另一个方法,而您不能在With块中执行此操作。
It seems that the only purpose of With Newis that it allows you to avoid an explicit variable declaration, instead causing the compiler to do it implicitly. Call me crazy, but I see no advantage in this.
似乎唯一的目的With New是它允许您避免显式变量声明,而不是导致编译器隐式执行它。叫我疯了,但我看不出这有什么好处。
In fact, I can say that I have honestly never seen any actual code that uses this syntax. The only thing I can find on Google is nonsense like this(and Callis a much better alternative there anyway).
事实上,我可以说老实说我从未见过任何使用这种语法的实际代码。我在谷歌上唯一能找到的就是这样的废话(Call无论如何都是更好的选择)。
UsingStatements/Blocks
Using语句/块
Unlike With, Usingis incrediblyuseful and should appear frequently in typical VB.NET code. However, it is very limited in its applicability: it works onlywith objects whose type implements the IDisposableinterface pattern. You can tell this by checking to see whether the object has a Disposemethod that you're supposed to call whenever you're finished with it in order to release any unmanaged resources.
不像With,Using是极其有益的,应当在典型的VB.NET代码频繁出现。但是,它的适用性非常有限:它仅适用于类型实现IDisposable接口模式的对象。您可以通过检查该对象是否具有Dispose在您完成它时应该调用的方法以释放任何非托管资源来判断这一点。
That is, by the way, a rule you should always follow when an object has a Disposemethod: you should alwayscall it whenever you're finished using the object. If you don't, it's not necessarily the end of the world—the garbage collector might save your bacon—but it's part of the documented contract and always good practice on your part to call Disposefor each object that provides it.
也就是说,顺便说一句,当一个对象有一个Dispose方法时,你应该始终遵循一个规则:当你使用完该对象时,你应该总是调用它。如果你不这样做,这不一定是世界末日——垃圾收集器可能会拯救你的培根——但它是文档化契约的一部分,并且始终是你调用Dispose提供它的每个对象的良好实践。
If you try to wrap the creation of an object that doesn'timplement IDisposablein a Usingblock, the compiler will bark at you and generate an error. It doesn't make sense for any other types because its function is essentially equivalent to a Try/Finallyblock:
如果您尝试将未IDisposable在Using块中实现的对象的创建包装起来,编译器将对您咆哮并生成错误。它对任何其他类型都没有意义,因为它的功能本质上等同于Try/Finally块:
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
But that's ugly and becomes rather unwieldy when you start nesting (like if we'd created a Penobject that needed to be disposed as well). Instead, we use Using, which has the same effect:
但这很丑陋,并且在您开始嵌套时变得相当笨拙(就像我们创建了一个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!]
The Usingstatement works both with objects you are first acquiring (using the Newkeyword or by calling a method like CreateGraphics), andwith objects that you have already created. In both cases, it ensures that the Disposemethod gets called, even if an exception gets thrown somewhere inside of the block, which ensures that the object's unmanaged resources get correctly disposed.
该Using语句既适用于您首次获取的对象(使用New关键字或调用类似 的方法CreateGraphics),也适用于您已经创建的对象。在这两种情况下,它确保Dispose方法被调用,即使在块内的某处抛出异常,这确保对象的非托管资源得到正确处理。
It scares me a little bit that you have written code in VB.NET withoutknowing about the Usingstatement. You don't use it for the creation of all objects, but it is very important when you're dealing with objects that implement IDisposable. You definitely should go back and re-check your code to ensure that you're using it where appropriate!
我有点害怕你在 VB.NET 中编写代码而不知道Using语句。您不会将它用于创建所有对象,但在处理实现IDisposable. 您绝对应该返回并重新检查您的代码,以确保您在适当的地方使用它!
回答by djv
The difference is the Using With...End End
不同之处在于 Using With...End End
Using cn as New OleDBConnection(MyConnectionString)
With cn
' Do stuff with cn
End With
End using
Calls cn.Dispose()automatically when going out of scope (End Using). But in the With New...End
cn.Dispose()超出范围时自动调用( End Using)。但在With New...End
With New OleDbConnection(MyConnectionString)
' Do stuff
End With
.Dispose() is not explicitly called.
.Dispose() 没有被显式调用。
Also with the named object, you can create watches and ?cnin the immediate window. With the unnamed object, you cannot.
同样使用命名对象,您可以?cn在即时窗口中创建监视。对于未命名的对象,您不能。
回答by David Petty
Using connection... End Using : Be careful !!! This statement will close your database connection!
使用连接...结束使用:小心!!!此语句将关闭您的数据库连接!
In the middle of a module or form(s), i.e.adding or updating records, this will close the connection. When you try to do another operation in that module you will receive a database error. For connections, I no longer use it. You can use the Try... End Try wihthouth the Using statement.
在模块或表单中间,即添加或更新记录,这将关闭连接。当您尝试在该模块中执行其他操作时,您将收到数据库错误。对于连接,我不再使用它。您可以使用 Try... End Try withhthouth Using 语句。
I open the connection upon entry to the module and close it it upon exit. That solves the problem.
我在进入模块时打开连接并在退出时关闭它。这解决了问题。

