为什么在using语句中声明的变量被视为只读?

时间:2011-05-14 10:41:34

标签: c# .net using-statement object-lifetime

为什么using变量被视为只读?它是c#语言规范还是托管语言规范?这是因为c#是.net语言?提前谢谢。

注意:using变量是使用语句

中出现的变量

示例代码:

using (Form s = new Form)
{
    myfunc(ref s);
}

我们无法在使用块中更改using变量的值。代码会引发错误。

注意:我不希望您讨论readonly关键字。

4 个答案:

答案 0 :(得分:11)

我正在看一个(过时的?)规范[1]。

15.13表示您在资源获取部分中声明的变量是只读的。那就是:

var form = new Form1();
using (form) {
    form = null;
}

有效,但

using (var form = new Form1()) {
    form = null;
}

没有。 这回答了部分问题(即为什么?因为它是规范的一部分......),但我知道这并不令人满意。但你为什么要这么做?


编辑:在考虑了这个之后,让我为这条规则提供一个可能的解释:

你有

using (var something = new Foo()) {
   something = /* whatever */
}

并且编译器允许这样做。现在如果Foo需要大量非托管资源(也许这就是你想要首先使用using的原因)?在使用块后,您无法再访问此引用。它没有被处理,因为你重新分配了something而忘了自己处理它。您根本无法保证GC运行。或者何时。您刚刚创建了一个模糊和隐藏的资源泄漏。


最后一个,受到Henk与Eric Lippert博客链接的启发,该博客最终再次向我们抛出规范:

  

表格的使用声明

     

使用(表达式)语句

     

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

换句话说:

var form = new Form1();
using (form) {
    form = null;
}

有效,因为它已扩展为

var form = new Form1();
var invisibleThing = form;
try {
   form = null;
} finally {
    if (invisibleThing != null) ((IDisposable)invisibleThing).Dispose();
}

因此,在这种情况下,您对using引用没有任何影响的事实只是对您隐藏,并且与前一种情况完全相同。

1:HTTP://www.ecma-international.org/publications/standards/Ecma-334.htm

答案 1 :(得分:4)

如果你的意思是在使用块开始时实例化的变量,那么它只是读取,因为它需要被放置在块的末尾。使用块的目的是以可预测的方式销毁资源,而不是等待垃圾收集器完成它的工作。

答案 2 :(得分:2)

首先,在您的示例中,ref修饰符很可能没有理由。

所以你问一个非常理论化的问题,它在实践中从来都不是问题。

带注释的C#3手册没有给出解释。

Eric Lippert在帖子about (not) Boxing in a using statement中触及了这个主题。

我自己捅了一下:

编译器使受控var只读,因为它可以。让这个var可写可以打开更多的蠕虫,请参阅Eric的Boxing文章。请注意,类似的规则适用于foreach()中的封闭变量。基本上,写入这些变量永远不会有用,因此编译器可以最大限度地控制它们。

答案 3 :(得分:1)

readonly是C#中的关键字。当您想要确保值永远不会在构造函数外部更改时,它非常有用。

当您为大型项目贡献代码时,此关键字可能会有所帮助,而您担心同事可能会尝试更改永远不应更改的变量。

编辑:我很好奇为什么有人对我的回答进行了低估。如果投票给谁,请告诉我我的答案错在哪里?感谢。