c# - 迭代变量如何只读?

标签 c# foreach iterator ienumerable cil

在C#规范的8.8.4中,提供了这个例子:

A foreach statement of the form

foreach (V v in x) embedded-statement

is then expanded to:

{
    E e = ((C)(x)).GetEnumerator();
    try {
        V v;
        while (e.MoveNext()) {
            v = (V)(T)e.Current;
            embedded-statement
        }
    }
    finally {
        … // Dispose e
    }
}

它还说:

The iteration variable corresponds to a read-only local variable with a scope that extends over the embedded statement.

The variable v is read-only in the embedded statement.

迭代变量如何设为只读?

在 C# 中你不能在这里使用 readonly,const 也不起作用。

这是我做的一个例子。

我查看了 CIL 代码,但看不到它使迭代变量只读的任何地方:

C#:

class Program
{
    static void Main(string[] args)
    {
        var enumerable = new List<string> { "a", "b" };

        foreach (string item in enumerable)
        {
            string x = item;
        }
    }
}

CIL:

.method private hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 80 (0x50)
    .maxstack 3
    .entrypoint
    .locals init (
        [0] class [mscorlib]System.Collections.Generic.List`1<string> enumerable,
        [1] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>,
        [2] string item,
        [3] string x
    )

    IL_0000: nop
    IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
    IL_0006: dup
    IL_0007: ldstr "a"
    IL_000c: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
    IL_0011: nop
    IL_0012: dup
    IL_0013: ldstr "b"
    IL_0018: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
    IL_001d: nop
    IL_001e: stloc.0
    IL_001f: nop
    IL_0020: ldloc.0
    IL_0021: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
    IL_0026: stloc.1
    .try
    {
        IL_0027: br.s IL_0035
        // loop start (head: IL_0035)
            IL_0029: ldloca.s 1
            IL_002b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current()
            IL_0030: stloc.2
            IL_0031: nop
            IL_0032: ldloc.2
            IL_0033: stloc.3
            IL_0034: nop

            IL_0035: ldloca.s 1
            IL_0037: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext()
            IL_003c: brtrue.s IL_0029
        // end loop

        IL_003e: leave.s IL_004f
    } // end .try
    finally
    {
        IL_0040: ldloca.s 1
        IL_0042: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
        IL_0048: callvirt instance void [mscorlib]System.IDisposable::Dispose()
        IL_004d: nop
        IL_004e: endfinally
    } // end handler

    IL_004f: ret
} // end of method Program::Main

最佳答案

迭代变量是只读的,因为写入它是一个错误。试一试,您就会知道。

它不会创建一个readonly 字段,文档中也没有说它会创建一个readonly 字段。它不可能是 readonly 字段,因为它不是字段。

现在,这是一个微妙的问题。假设 v 是可变值类型,您调用该类型的方法来改变 this 的字段,传递给 v。预测会发生什么。现在试试看;你是对的吗?你能解释一下发生了什么吗?您现在如何看待 v 是“只读”的说法?你会说这是一个错误,还是正确的行为?

现在用 readonly 字段尝试同样的事情,看看结果是什么。您认为这是正确的行为吗?

关于c# - 迭代变量如何只读?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57940961/

相关文章:

c++ - 迭代器上的 vector 下标超出范围

Java - 在一个映射中交换值和键?

c# - 在 if 条件中声明变量以在 C# 中进一步测试

c# - Silverlight AccordionItem HeaderTemplate 中的超链接

c# - Excel.Application 异常

Powershell:Foreach 不工作?

jakarta-ee - 如何访问c :forEach with a scriptlet/expression?中的迭代变量

c++ - 无法在 C++ 中创建模板<typename T> vector<T>::iterator

c# - IEnumerable<string> 到字典<char, IEnumerable<string>>

c# - 在C#中有条件的foreach循环