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

发布于 2024-11-06 20:27:44 字数 257 浏览 0 评论 0原文

为什么 using 块中的变量 (myform) 被视为只读,并且当我尝试将其作为函数的引用传递时,编译器会引发错误。

示例代码:

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

将使用变量作为 ref 传递给函数将引发错误。因此上面的代码会引发错误。

注意:“readonly”关键字与我的问题无关。

why variable (myform) in using block treated as read-only and the compiler raise an error when I try to pass it as a reference to a function.

sample code:

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

passing using variable to a function as ref will raise an error. thus the code above will raise an error.

Note : 'readonly' keyword is unrelated to my question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

唔猫 2024-11-13 20:27:44

我现在正在查看一个(过时的?)规范 [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 的原因)怎么办?在 using 块之后,您将无法再访问此引用。它没有被处理,因为您重新分配了某物并且忘记自己处理它。您根本无法保证 GC 会运行。或者什么时候。您刚刚创建了一个被掩盖和隐藏的资源泄漏。


最后一个,灵感来自 Henk 的 Eric Lippert 博客链接,该链接最终再次向我们抛出了规范:

以下形式的 using 语句

using(表达式)语句

具有相同的两种可能的扩展,但在本例中 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

I'm looking at an (outdated?) spec [1] right now.

15.13 says that variables that you declare in the resource acquisition part are readonly. That is:

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

works, but

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

doesn't.
This answers part of the question (i.e. Why? Because it is part of the spec..), but I understand that this is not really satisfying. But why would you even want to do that?


Edit: After thinking about this, let me offer a possible explanation for this rule:

You have

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

and the compiler allows this. Now what if Foo needs a lot of unmanaged resources (maybe that's the reason you wanted to use using in the first place)? After the using block you have no way to access this reference anymore. It wasn't disposed, because you reassigned something and forgot to handle it yourself. You don't have a guarantee that the GC runs, at all. Or when. You just created a resource leak that is obscured and hidden.


A final one, inspired by Henk's link to Eric Lippert's blog, which again just ends up throwing the spec at us:

A using statement of the form

using (expression) statement

has the same two possible expansions, but in this case ResourceType is
implicitly the compile-time type of the expression, and the resource variable
is inaccessible in, and invisible to, the embedded statement.

In other words:

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

works, because this is expanded to

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

So in this case the fact that you have no influence over the using reference is just hidden from you and is exactly like in the previous case.

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

埋情葬爱 2024-11-13 20:27:44

如果您的意思是在 using 块的开头实例化的变量,那么它是只读的,因为它需要在块的末尾进行处理。 using 块的要点是以可预测的方式销毁资源,而不是等待垃圾收集器完成其工作。

If you mean the variable instantiated at the start of a using block, then it's read only because it needs to be disposed at the end of the block. The point of a using block is to have a resource destroyed in a predictable way rather than waiting for the garbage collector to do it's job.

甜扑 2024-11-13 20:27:44

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

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

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

Eric Lippert 在一篇文章 关于(不是)using 语句中的装箱

我自己的尝试:

编译器将受控变量设为只读因为它可以。让这个 var 可写会带来更多的麻烦,请参阅 Eric 的 Boxing 文章。请注意,类似的规则适用于 foreach() 中的封闭变量。基本上,写入这些变量永远没有用,因此编译器对它们进行最大程度的控制。

First of all, in your example there is most likely no reason for the ref modifier.

So you're asking a very theoretical question, it never is a problem in practice.

The annotated C#3 manual does not give an explanation.

Eric Lippert touches on the subject in a post about (not) Boxing in a using statement.

My own stab at it:

The compiler makes the controlled var readonly because it can. Leaving this var writeable would open up even more cans of worms, see the Boxing article from Eric. Note that a similar rule applies to the enclosed variable in a foreach(). Basically, writing to these vars would never be useful, so the compiler takes maximum control over them.

如果没有 2024-11-13 20:27:44

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

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

编辑:我很好奇为什么有人对我的回答投了反对票。谁投了反对票,你能告诉我我的答案哪里错了吗?谢谢。

readonly is a keyword in C#. It's useful when you want to ensure the value never changes outside a constructor.

This keyword could be helpful when you're contributing code to a large project and you're worried coworkers might try to change a variable that should never be altered.

Edit: I'm curious why someone downvoted my answer. Whoever downvoted can you please show my where my answer is wrong? Thanks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文