为什么结构中的迭代器可以修改它?

SLa*_*aks 11 .net c# iterator this value-type

我发现允许修改值类型中的迭代器方法this.
但是,由于CLR的限制,调用方法看不到修改.(this按值传递)

因此,迭代器和非迭代器中的相同代码会产生不同的结果:

static void Main() {
    Mutable m1 = new Mutable();
    m1.MutateWrong().ToArray();     //Force the iterator to execute
    Console.WriteLine("After MutateWrong(): " + m1.Value);

    Console.WriteLine();

    Mutable m2 = new Mutable();
    m2.MutateRight();
    Console.WriteLine("After MutateRight(): " + m2.Value);
}

struct Mutable {
    public int Value;

    public IEnumerable<int> MutateWrong() {
        Value = 7;
        Console.WriteLine("Inside MutateWrong(): " + Value);
        yield break;
    }
    public IEnumerable<int> MutateRight() {
        Value = 7;
        Console.WriteLine("Inside MutateRight(): " + Value);
        return new int[0];
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Inside MutateWrong(): 7
After MutateWrong(): 0

Inside MutateRight(): 7
After MutateRight(): 7

为什么在迭代器中改变结构是不是编译器错误(或至少是警告)?
这种行为是一个微妙的陷阱,不容易理解.

匿名方法,它们共享相同的限制,不能使用this在所有.

注意:可变结构是邪恶的 ; 这应该永远不会出现在实践中.

Gab*_*abe 2

为了证明警告的合理性,应该是在程序员可能得到意外结果的情况下。埃里克·利珀特 (Eric Lippert) 表示,“我们尝试只在那些我们几乎可以肯定地说代码已损坏、具有误导性或无用的情况下保留警告。” 这是一个警告可能会产生误导的例子。

\n

假设你有这个完全有效的 \xe2\x80\x93 如果不是非常有用的 \xe2\x80\x93 对象:

\n
struct Number\n{\n    int value;\n    public Number(int value) { this.value = value; }\n    public int Value { get { return value; } }\n    // iterator that mutates "this"\n    public IEnumerable<int> UpTo(int max)\n    {\n        for (; value <= max; value++)\n            yield return value;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

你有这个循环:

\n
var num = new Number(1);\nforeach (var x in num.UpTo(4))\n    Console.WriteLine(num.Value);\n
Run Code Online (Sandbox Code Playgroud)\n

您希望这个循环打印1,1,1,1,而不是1,2,3,4,对吗?所以该类完全按照您的预期进行。在这种情况下,警告是不合理的。

\n

由于这显然不是代码被破坏、误导或无用的情况,您如何建议编译器生成错误或警告?

\n