我知道当您拥有以下代码时,会在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...
}
答案 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.
编译但访问已处置的对象。