C#:using block:对象重新初始化

PRR*_*PRR 5 c# using

在"使用"块内重新初始化是一个坏主意,在任何时候都要避免.我还是会问这个:

为什么"使用"调用处理原始值而不是最后一个引用或重新初始化(如果使用try finally block则会发生这种情况)

MyClass b = new MyClass();// implements Idisposable
MyClass c = new MyClass();
MyClass a ; 

 using (a = new MyClass())
 {
                a = b;
                a = c;
 }
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,dispose将在原始引用上调用,而不是在引用时更新.这可以通过在dispose方法中在控制台上打印一些内容来轻松验证.

然而,使用try {} finally代码调用最后一个引用dispose方法.

try
{
   a = new MyClass();
   a = b;
   a = c;
 }
  finally 
   {
   a.Dispose();
  }
Run Code Online (Sandbox Code Playgroud)

MSDN:using语句确保即使在对象上调用方法时发生异常,也会调用Dispose.

using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}
Run Code Online (Sandbox Code Playgroud)

基本上"使用"转换为:

{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}
Run Code Online (Sandbox Code Playgroud)

Meh*_*ari 8

usingC#规范中定义了两种形式的语句:

using-statement:
    using   (    resource-acquisition   )    embedded-statement
resource-acquisition:
    local-variable-declaration
    expression
Run Code Online (Sandbox Code Playgroud)

如果你有local-variable-declaration,那就不会有任何问题.该变量在使用块中是只读的,您根本无法更改它.规范说:

8.13使用声明

[...]在任一扩展中,资源变量在嵌入语句中是只读的.

在这里,我们正在处理的第二种形式:其中,resource-acquisitionexpression与不是local-variable-declaration.在这种情况下,C#规范清楚地说:

表格的使用声明

 using (expression) statement
Run Code Online (Sandbox Code Playgroud)

具有相同的两个可能的扩展,但在这种情况下,ResourceType隐式地是表达式的编译时类型,并且资源变量在嵌入语句中是不可访问的,并且是不可访问的.[强调我的]

显然,您无法更改不可见的,无法访问的变量.其值仅在using resource-acquisition子句中指定.因此,它将具有变量的旧值,而不是新值.

当您处理已声明变量的赋值时,您正在使用此using语句形式.您的事实给一个变量赋值一样

using ( x = something )
Run Code Online (Sandbox Code Playgroud)

是无关紧要的.整体x = something被视为表达,只有表达的价值才是重要的.重要的是要知道"资源变量"在这里不是"x".这是一个看不见的变量.从编译器的角度来看,以下构造之间没有太大区别:

using ( something ) 
using ( x = something )
using ( y = x = something )
Run Code Online (Sandbox Code Playgroud)

在所有情况下,表达式都将被执行,将被保证处理,而不是变量.如果这不是定义的行为并且您在上面的块中编写了第三行,编译器应该做什么?配置xy?都?都不是?目前的行为是有道理的.

  • @silky:我不认为"干"与正确性有任何关系.我相信,干或不干,这是唯一有意义的事情.规范是这个问题的唯一权威来源,并且**要求**这样的行为; 其他一切都是猜测.显然,语言可以选择通过另一种方法实现其"使用"语句,因为它不是技术限制,而是设计决策. (2认同)

Han*_*ant 3

编译器生成此代码:

MyClass b = new MyClass();
MyClass a;
MyClass cs$3$000 = a = new MyClass();
try {
  a = b;
}
finally {
  if (cs$3$000 != null) cs$3$000.Dispose();
}
Run Code Online (Sandbox Code Playgroud)

自动生成的 cs$3$000 局部变量实现了合约。