Dan*_*Tao 11 c# struct specifications using mutable
这个问题真的是这个问题的一个分支,但我认为它应该得到自己的答案.
根据ECMA-334第15.13节(关于using声明,以下称为资源获取):
在资源获取中声明的局部变量 是只读的,并且应包括初始化器.如果嵌入语句试图修改这些局部变量(通过赋值或发生编译时间错误
++和--操作员)或它们传递作为ref或out参数.
这似乎解释了为什么下面的代码是非法的.
struct Mutable : IDisposable
{
public int Field;
public void SetField(int value) { Field = value; }
public void Dispose() { }
}
using (var m = new Mutable())
{
// This results in a compiler error.
m.Field = 10;
}
Run Code Online (Sandbox Code Playgroud)
但是这个怎么样?
using (var e = new Mutable())
{
// This is doing exactly the same thing, but it compiles and runs just fine.
e.SetField(10);
}
Run Code Online (Sandbox Code Playgroud)
上述代码段在C#中是否未定义和/或非法?如果它是合法的,那么这段代码与上述规范的摘录之间有什么关系?如果它是非法的,为什么它有效?是否有一些允许它的微妙漏洞,或者它的作用仅仅归因于运气(因此人们不应该依赖这种看似无害的代码的功能)?
我怀疑它编译和运行的原因是SetField(int)函数调用,而不是赋值或ref参数out调用。编译器(通常)无法知道是否SetField(int)会改变变量。
根据规范,这似乎完全合法。
并考虑替代方案。在 C# 编译器中,用于确定给定函数调用是否会改变值的静态分析显然成本过高。该规范旨在在所有情况下避免这种情况。
另一种选择是 C# 不允许对语句中声明的值类型变量进行任何方法调用using。这可能不是一个坏主意,因为IDisposable在结构上实现无论如何都是自找麻烦。但是,当 C# 语言首次开发时,我认为他们对以许多有趣的方式使用结构体寄予厚望(正如GetEnumerator()您最初使用的示例所示)。