C#处理对象

时间:2010-10-15 17:52:33

标签: c# dispose idisposable

我知道当您拥有以下代码时,会在StreamReader对象上调用Dispose()方法:

//Sample 1
using (StreamReader sr1 = new StreamReader(@"C:\Data.txt"))
{
    string s1 = sr1.ReadToEnd();
    //Do something with s1...
}

但是如果你编写这样的代码(样本2),也会调用Dispose()方法吗?

//Sample 2
StreamReader sr2 = new StreamReader(@"C:\Data.txt");
using (sr2)
{
    string s2 = sr2.ReadToEnd();
    //Do something with s2...
}

6 个答案:

答案 0 :(得分:9)

是的,绝对的。详情见第8.13节。没有关于您的确切问题的简明陈述,但是:

  

表格的使用声明

using (expression) statement
     

具有相同的三种可能的扩展,但在这种情况下,ResourceType隐式地是表达式的编译时类型,并且资源变量在嵌入语句中是不可访问的,并且是不可见的。

提到的“三种可能的扩展”涵盖了同时声明变量的更常见情况。基本上重要的是除了变量的范围外,它的行为方式相同。仍然会调用Dispose - 否则根本没有提出using声明:)

请注意,就块中的有效内容而言,两者不是完全等效,因为using语句声明的变量是只读的。所以这是有效的:

// Warning but no error
MemoryStream ms = new MemoryStream();
using (ms)
{
    ms = null;
}

但这不是:

using (MemoryStream ms = new MemoryStream())
{
    // error CS1656: Cannot assign to 'ms' because it is a 'using variable'
    ms = null;
}

请注意,即使在有效的情况下,它也是ms原始值,用于处理。编译器清楚地说明了这一点:

  

警告CS0728:可能错误地分配给本地'ms',这是using语句或lock语句的参数。处理呼叫或解锁将发生在本地的原始值上。

请注意,表单不会生成警告:

// No warning
MemoryStream ms;
using (ms = new MemoryStream())
{
    ms = null;
}

另一方面,除此之外,他们真的会以同样的方式行事。

编辑:正如bzlm所说,在using语句之后变量仍然在范围内的事实意味着它通常 并不是一个好主意。但是,已经处置的对象总是不可用。例如:

MemoryStream ms = new MemoryStream();
using (ms) 
{
    // Do stuff
}
byte[] data = ms.ToArray();

这样可以正常工作 - MemoryStream即使在处理数据时也会保留数据。虽然我觉得有点不对劲。

答案 1 :(得分:9)

是的,在两个示例中都会调用Dispose()。除了在第二个示例中,已处置的StreamReader仍在范围内,它们在功能上是等效的。因此,第一种方法是首选方法,因为使用已处置的对象通常是一个坏主意。

然而正如其他人所指出的那样,使用被处置物体有时是可以的。在这种情况下,您可能想要使用第二个示例。但是你必须知道你在做什么,如果可能的话我会避免它。

答案 2 :(得分:0)

这两个代码几乎相同。一旦控制离开使用块,将调用Dispose。如果在此之前发生异常,则在任何一种情况下都不会调用它。但除了异步异常之外,这不会发生在您的代码中。

Is C#'s using statement abort-safe?

类似的讨论是关注与线程堕胎的相互作用。

答案 3 :(得分:0)

using接受一个实现IDisposable的对象。当编译器生成代码以在Dispose块的末尾调用using时,不会考虑创建该对象的方式和位置。

答案 4 :(得分:0)

好问题。我会说是的,因为using代码块仅仅是以下语法糖:

try
{
   var myObj = <parameter from using>
   <using block code>
}
finally
{
   myObj.Dispose();
}

请注意,在替换using块时,您最终处置的变量具有另一个在代码块(sr2)外可见的句柄。这个引用将阻止实例在using语句之后被垃圾收集,但是因为它被处理掉了,除非它足够聪明以从中间范围的Dispose()中恢复,否则它将没有多大用处。

答案 5 :(得分:0)

MSDN表示初始化期间的异常并不完全相同。还要考虑以下范围设定方案:

//Sample 1
using (StreamReader sr1 = new StreamReader(@"C:\Data.txt"))
{
    string s1 = sr1.ReadToEnd();
    //Do something with s1...
}
sr1.ReadToEnd() // sr1 not in scope.

不编译,但

//Sample 2
StreamReader sr2 = new StreamReader(@"C:\Data.txt");
using (sr2)
{
    string s2 = sr2.ReadToEnd();
    //Do something with s2...
}

sr2.ReadToEnd() // possible to write, but accessing a disposed object.

编译但访问已处置的对象。