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在所有.
注意:可变结构是邪恶的 ; 这应该永远不会出现在实践中.
为了证明警告的合理性,应该是在程序员可能得到意外结果的情况下。埃里克·利珀特 (Eric Lippert) 表示,“我们尝试只在那些我们几乎可以肯定地说代码已损坏、具有误导性或无用的情况下保留警告。” 这是一个警告可能会产生误导的例子。
\n假设你有这个完全有效的 \xe2\x80\x93 如果不是非常有用的 \xe2\x80\x93 对象:
\nstruct 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}\nRun Code Online (Sandbox Code Playgroud)\n你有这个循环:
\nvar num = new Number(1);\nforeach (var x in num.UpTo(4))\n Console.WriteLine(num.Value);\nRun Code Online (Sandbox Code Playgroud)\n您希望这个循环打印1,1,1,1,而不是1,2,3,4,对吗?所以该类完全按照您的预期进行。在这种情况下,警告是不合理的。
由于这显然不是代码被破坏、误导或无用的情况,您如何建议编译器生成错误或警告?
\n