更新:好吧,现在我已经完成了它:我向微软提交了一个关于此的错误报告,因为我严重怀疑这是正确的行为.那就是说,我仍然不能100%肯定对这个问题有什么看法; 所以我可以看到什么是"正确的"是开放的某种程度的解释.
我的感觉是,微软会接受这是一个错误,或者回应一个using语句中的可变值类型变量的修改构成未定义的行为.
此外,对于它的价值,我至少猜测这里发生了什么.我怀疑编译器正在为闭包生成一个类,将局部变量"提升"到该类的实例字段; 因为它在一个using街区内,所以它正在建造这个领域readonly.正如LukeH在对另一个问题的评论中指出的那样,这会阻止方法调用,例如MoveNext修改字段本身(它们会影响副本).
注意:我已经缩短了这个问题的可读性,尽管它仍然不是很短.有关完整的原始(较长)问题,请参阅编辑历史记录.
我已经阅读了我认为是ECMA-334相关章节的内容,似乎无法找到这个问题的结论性答案.我将首先说明问题,然后为感兴趣的人提供一些附加评论的链接.
如果我有一个可实现的可变值类型IDisposable,我可以(1)调用一个方法来修改using语句中局部变量值的状态,并且代码的行为与我期望的一样.但是,一旦我在语句中的闭包内捕获了有问题的变量using,(2)在本地范围内不再可以看到对值的修改.
只有在闭包内和using语句中捕获变量的情况下,此行为才会显现; 当只有一个(using)或其他条件(闭包)存在时,这是不明显的.
为什么在using语句中的闭包内捕获可变值类型的变量会改变其本地行为?
下面是说明第1项和第2项的代码示例.两个示例都将使用以下演示Mutable值类型:
struct Mutable : IDisposable
{
int _value;
public int Increment()
{
return _value++;
}
public void Dispose() { }
}
Run Code Online (Sandbox Code Playgroud)
using块中变换值类型变量using (var x = new …Run Code Online (Sandbox Code Playgroud) 我对以下代码有一些疑问:
using System;
namespace ConsoleApplication2
{
public struct Disposable : IDisposable
{
public void Dispose() { }
}
class Program
{
static void Main(string[] args)
{
using (Test()) { }
}
static Disposable Test()
{
return new Disposable();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
Disposable结构进行操作的using语句是否会从Test()结构框中返回?为了试图找出自己,我检查了上面代码生成的IL,这里是Main(...)方法的IL :
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] valuetype ConsoleApplication2.Disposable CS$3$0000)
L_0000: call valuetype ConsoleApplication2.Disposable ConsoleApplication2.Program::Test()
L_0005: stloc.0
L_0006: …Run Code Online (Sandbox Code Playgroud) struct ×2
.net ×1
boxing ×1
c# ×1
closures ×1
idisposable ×1
ienumerator ×1
mutable ×1
using ×1