迭代变量如何为只读? [英] How is the iteration variable readonly?

查看:102
本文介绍了迭代变量如何为只读?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C#规范的8.8.4中,它提供了以下示例:

In 8.8.4 of the C# specification, it provides this example:

形式的foreach语句

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.

变量v在嵌入式语句中为只读.

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

迭代变量如何设置为只读?

在C#中,您不能在此处使用只读模式,而const也不起作用.

In C# you can't use readonly here, and const doesn't work either.

这是我做的一个例子.

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

I viewed the CIL code but can't see anywhere where it makes the iteration variable readonly:

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

推荐答案

编译器中有特殊情况的代码,该代码对foreach块中的迭代变量强制执行只读约束.它与该语言中公开的任何修饰符都不对应,因此您无法在此特定语法之外将局部变量显式声明为只读.

There is special-case code in the compiler which enforces the read-only constraint on the iteration variable in a foreach block. It does not correspond to any modifier which is exposed in the language, so you can't explicitly declare local variables as read-only outside of this particular syntax.

从概念上讲,此约束是在扩展之前 应用的.也就是说,如果对迭代变量有任何分配,则编译器将生成错误.否则,代码将被扩展.在扩展的代码中,由于v只是常规的局部变量,因此没有特别的限制.因此,IL中也不存在该约束.

Conceptually, this constraint is applied before the expansion. That is, if there are any assignments to the iteration variable, the compiler generates an error. Otherwise the code is expanded. In the expanded code there is no particular constraints on v since it is just a regular local variable. Therefore the constraint does not exist in the IL either.

那么为什么foreach语法的这种特殊情况的只读约束吗?只有语言设计者才能回答这个问题,但我想这只是为了避免混淆.如果迭代器变量是可分配的,则您可以认为能够以这种方式修改实际的集合,但是由于底层的枚举器是只读的,因此实际上不会发生任何事情.

So why is there this special-case read-only constraint with the foreach-syntax? Only the language designers can answer that, but I would guess it is just to avoid confusion. If the iterator variable was assignable, you might think you were able to modify the actual collection that way, but nothing would actually happen, since the underlying enumerator is read-only.

这篇关于迭代变量如何为只读?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆