C#:使用块:对象重新初始化
在“using”块内重新初始化是一个坏主意,应始终避免。我仍然要问这个:
为什么“using”调用 dispose 是在原始值上,而不是在最后一个引用或重新初始化上(如果使用 try finally 块,则会发生这种情况)
MyClass b = new MyClass();// implements Idisposable
MyClass c = new MyClass();
MyClass a ;
using (a = new MyClass())
{
a = b;
a = c;
}
在上面的代码中,将在原始引用上调用 dispose而不是较新的引用。这可以通过在 dispose 方法中在控制台上打印一些内容来轻松验证。
但是,使用 try{} finally 代码,将调用最后一个引用的 dispose 方法。
try
{
a = new MyClass();
a = b;
a = c;
}
finally
{
a.Dispose();
}
MSDN :using 语句确保即使发生异常也会调用 Dispose当您调用对象的方法时。
using (Font font1 = new Font("Arial", 10.0f))
{
byte charset = font1.GdiCharSet;
}
基本上“使用”翻译为:
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
Re-initialization within "using" block is a bad idea, to be avoided at all times. Still i am going to ask this:
Why does "using" call dispose on the original value and not on the last reference or re-initialization (which happens if try finally block is used)
MyClass b = new MyClass();// implements Idisposable
MyClass c = new MyClass();
MyClass a ;
using (a = new MyClass())
{
a = b;
a = c;
}
In the above code dispose will be called on original reference and not the newer referenced. This can be easily verified by printing something on console in the dispose method.
However with try{} finally code the last reference dispose method is called.
try
{
a = new MyClass();
a = b;
a = c;
}
finally
{
a.Dispose();
}
MSDN : The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object.
using (Font font1 = new Font("Arial", 10.0f))
{
byte charset = font1.GdiCharSet;
}
Basically "using" translates to:
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
C# 规范中定义了两种形式的
using
语句:如果您有一个
local-variable-declaration
,就不会有任何问题。该变量在 using 块中将是只读的,您根本无法更改它。规范说:在这里,我们处理第二种形式:其中
资源获取
是表达式
,而不是本地变量声明
。在这种情况下,C# 规范明确指出:显然,您无法更改不可见、无法访问的变量。它的值仅在 using
resource-acquisition
子句中分配。因此,它将具有变量的旧值,而不是新值。当您处理对已声明变量的赋值时,您正在使用这种形式的
using
语句。事实上,您为变量赋值是无关紧要的。整个
x = Something
被视为一个表达式,只有该表达式的值才是重要的。重要的是要知道这里的“资源变量”不是“x”。这是一个看不见的变量。从编译器的角度来看,以下构造之间没有太大区别:在所有情况下,表达式都会被执行,并且值将得到保证的处置,而不是变量。如果这不是定义的行为并且您在上面的块中编写了第三行,编译器应该做什么?处置
x
?是吗?两个都?两者都不?目前的行为是有道理的。There are two forms of
using
statements defined in the C# specification:If you have a
local-variable-declaration
, there wouldn't be any questions. The variable will be read-only in the using block and you can't change it at all. The spec says:Here, we're dealing with the second form: where
resource-acquisition
isexpression
and not alocal-variable-declaration
. In which case, the C# spec clearly says:Obviously, you can't change an invisible, inaccessible variable. Its value is assigned only in the using
resource-acquisition
clause. Therefore, it'll have the old value of the variable, not the new one.When you are dealing with an assignment to an already declared variable, you are using this form of the
using
statement. The fact that you are assigning a value to a variable likeis irrelevant. The whole
x = something
is treated as an expression and only the value of that expression is what matters. It's important to know that "resource variable" is not "x" here. It's an invisible variable. From the compiler's perspective, there's not much difference between the following constructs:In all cases, the expression will get executed and the value is what will get guaranteed disposal, not the variable. What would the compiler supposed to do if this wasn't the defined behavior and you had written the third line in the above block? Dispose
x
?y
? both? neither? The current behavior makes sense.编译器生成以下代码:
自动生成的 cs$3$000 局部变量实现合约。
The compiler generates this code:
The auto-generated cs$3$000 local variable implements the contract.
using 可以看作是对使用 using 声明的对象调用 Dispose 的承诺。恕我直言,这是唯一有意义的事情!
如果您对重新分配的值调用 dispose,则原始值将不会被释放。
The using can be seen as a promise to call disposed on the object declared with using. This is the only thing that, IMHO, makes sense!
If you would call dispose on the reassigned value, then the original value will not be disposed.
似乎“using”正在创建它自己的变量来存储引用,该变量被初始化为“a”,而“a”又被初始化为对象的第一个实例。稍后,当您更改“a”时,您并没有真正更改存储在“using”语句中的原始引用。这似乎是一个非常好的功能,因为 using 负责处理 using 语句中提到的实际对象,而不是变量。
It seems that the "using" is creating it's own variable to store the reference, that gets initialized to "a" which in turn is initialized to the first instance of the object. Later when you change "a", you're not really changing the original reference that was stored in the "using" statement. It seems like a pretty good feature, since the using is responsible for disposing the actual object mentioned in the using statement, not the variable.
是的,这很有趣。
所以我查看了反编译的代码:
所以它确实复制了引用,并稍后使用它的副本,允许您重置变量,而就终结器而言,没有真正实现任何目标。
实际上,如果您只能在 using 语句中使用“只读”变量,那就太好了。有点令人困惑。当然,MSDN 具有误导性。
Yeah, it's interesting.
So I looked at the decompiled code:
So it really copies the reference, and uses it's copy later, allowing you to reset the variable, without really achieving anything, in terms of the finaliser.
Really, it would be nice if you could only use 'read-only' variables in the using statement. It's a little confusing. And certainly, the MSDN is misleading.
将在 using 子句的参数中引用的对象上调用 Dispose。就是这么简单。
Dispose will be called on the object referenced in the argument of the using clause. It's that simple.