Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 无法分配给项,因为它是foreach迭代变量_C#_Foreach_Iterator_Ienumerable_Ienumerator - Fatal编程技术网

C# 无法分配给项,因为它是foreach迭代变量

C# 无法分配给项,因为它是foreach迭代变量,c#,foreach,iterator,ienumerable,ienumerator,C#,Foreach,Iterator,Ienumerable,Ienumerator,为什么我们不能给foreach循环中的局部变量赋值 我知道这不会更新集合,因为我们只是更改局部变量引用的对象 如果使用while循环实现相同的功能,则允许您更新局部变量 class Program { static void Main(string[] args) { IEnumerable<string> enumerable = new List<string> { "a", "b", "c" }; //This fo

为什么我们不能给foreach循环中的局部变量赋值

我知道这不会更新集合,因为我们只是更改局部变量引用的对象

如果使用while循环实现相同的功能,则允许您更新局部变量

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

        //This foreach loop does not compile:
        foreach (string item in enumerable)
        {
            item = "d"; //"cannot assign to item because it is a foreach iteration variable"
        }

        //The equivalent C# code does compile and allows assinging a value to item:            
        var enumerator = enumerable.GetEnumerator();
        try
        {
            while (enumerator.MoveNext())
            {
                string item = (string)enumerator.Current;
                item = "d";
            }
        }
        finally
        {
            enumerator.Dispose();
        }
    }
}
类程序
{
静态void Main(字符串[]参数)
{
IEnumerable enumerable=新列表{“a”、“b”、“c”};
//此foreach循环不编译:
foreach(可枚举中的字符串项)
{
item=“d”;/“无法分配给item,因为它是foreach迭代变量”
}
//等效的C#代码编译并允许将值分配给项:
var enumerator=enumerable.GetEnumerator();
尝试
{
while(枚举数.MoveNext())
{
字符串项=(字符串)枚举器.Current;
项目=“d”;
}
}
最后
{
枚举数。Dispose();
}
}
}
编辑:
这个问题不同于可能的重复,因为它是在问为什么我们不能修改迭代变量,而在幕后它只是一个局部变量,指向与
枚举器相同的对象。Current

我修改了你的代码,所以它们实际上是等价的:

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<string> enumerable = new List<string> { "a", "b", "c" };
        foreach (string element in enumerable)
        {
            object item = element;
            item = "d"; 
        }

        IEnumerator enumerator = enumerable.GetEnumerator();
        while (enumerator.MoveNext())
        {
            object item = enumerator.Current;
            item = "d";
        }
    }
}
我使用.NETSDK4.7.2附带的csc.exe进行编译,然后使用ILDASM可视化生成的MSIL(显示并排差异的屏幕截图)。方法、设置、变量声明等的初始部分相同,但对于无操作:

与循环体一样:

唯一可辨别的区别在于处理方式;我对追查原因不太感兴趣

因此,很明显,编译器会按照所示的方式重写该方法。您最初的问题只能由编写编译器的人来回答,但在我看来,这是禁止分配给
枚举数的扩展。当前的
-阻止这样做没有意义,但允许您分配给foreach循环中声明的与其等价的变量。很明显,这是一个直接评估的特例,从错误消息与foreach循环的通信方式来看


我还想说(观点部分),阻止对foreach循环迭代器变量的赋值可以防止伤害/意外后果/模糊的bug,我看不出有什么缺点。如果你想要一个变量,你可以重新分配;再做一个

根据Eric Lippert的说法,
迭代变量是只读的,因为写入它是一个错误

看起来编译器中有一些规则阻止您编译试图修改迭代变量的代码,即使它在幕后没有标记为
readonly
(因为它是本地变量,所以无论如何也不能)


我写了一篇文章,其中包含了我在学习
IEnumerable
/
foreach

时提出的所有问题/答案,“等效的C#code确实可以编译”不!这与您在
foreach
循环中尝试执行的操作不同。在
while
循环中,您为对象创建了一个新引用,然后为其指定了一个不同的值<代码>枚举器。当前=“d”
也不起作用,同样的原因是,
枚举器。当前的
是只读的。@AhmedAbdelhameed这与Caius Jard下面的答案相反。请看下面我的评论。另一方面,你的问题与可能重复的问题类似,而被接受的答案回答了“为什么”的问题。简单的答案是“因为迭代器是只读的”。欲了解更多信息,请点击这里。请特别检查第二个答案,以了解为什么它是只读的。@AhmedAbdelhameed这里有一个例子,它显示了一个局部变量,该变量指向与当前对象相同的对象:在这种情况下,标记的重复项应该充分解决您的问题,以及有关堆栈溢出的许多其他类似问题。事实上,如果这真的是你的意思,这个问题不是很有用,因为它总是有相同的答案:“因为这是语言的规则,编译器强制执行”。您也可以问这样的问题:“为什么
internal
对程序集外部的代码隐藏成员”,或者“为什么使用
产生返回的方法必须具有
IEnumerable
IEnumerator
IEnumerable
IEnumerable
的返回类型?”?我根据跟踪调查进行了编辑,我最初的记忆是正确的;变量用于调整仅供参考,您编写的等效代码仅适用于C#4及更低版本(visual studio 2010及更高版本)。在C#5及更新版本(visual studio 2012及更新版本)中,
字符串e在while循环内部而不是外部声明。请看问题中的注释好吧,我确实说了我使用的编译器。。。它相对来说是问题本身的附属品(这可能应该作为离题而结束,因为它本质上是在询问编译器团队为什么做出这样的决定)@Backwards\u Dave:你说“我应该能够更新这个变量”。不,你不应该。这是一个只读的局部变量,所以你不应该更新它。@ BuffWrdsdave:所以这里有一个有趣的问题让你考虑。假设循环包含一个
await
,并且循环变量在
await
之前和之后都被访问。尝试反编译;关于循环变量的具体化,您现在发现了什么?请发表评论?
IEnumerable<string> enumerable = new List<string> { "a", "b", "c" };

//you write
foreach (string element in enumerable)
{
    Console.WriteLine(element);
}

//the compiler writes
string element;   
var enumerator = enumerable.GetEnumerator();
try
{
    while (enumerator.MoveNext())
    {
        element = enumerator.Current;

        //begin your foreach body code
        Console.Write(element); 
        //end your foreach body code
    }
}
finally
{
    enumerator.Dispose();
}
static void ForEachWay(){


    var enumerable = new List<string>();
    enumerable.Add("a");
    enumerable.Add("b");
    enumerable.Add("c");

    //you write
    foreach (string element in enumerable)
    {
        Console.WriteLine(element);
    }

}

static void EnumWayWithLoopVar(){
    var enumerable = new List<string>();
    enumerable.Add("a");
    enumerable.Add("b");
    enumerable.Add("c");

    string e;
    var enumerator = enumerable.GetEnumerator();
    try{ 
        while (enumerator.MoveNext())
        {
            e = enumerator.Current;
            Console.Write(e); 
        }
    }finally{
        enumerator.Dispose();
    }

}