简体   繁体   English

为什么赋值运算符(=)在foreach循环中无效?

[英]Why are assignment operators (=) invalid in a foreach loop?

Why are assignment operators (=) invalid in a foreach loop? 为什么赋值运算符(=)在foreach循环中无效? I'm using C#, but I would assume that the argument is the same for other languages that support foreach (eg PHP). 我正在使用C#,但我认为该参数对于支持foreach其他语言(例如PHP)是相同的。 For example, if I do something like this: 例如,如果我这样做:

string[] sArray = new string[5];

foreach (string item in sArray)
{
   item = "Some assignment.\r\n";
}

I get an error, "Cannot assign to 'item' because it is a 'foreach iteration variable'." 我收到一个错误,“无法分配给'item',因为它是'foreach迭代变量'。”

Here's your code: 这是你的代码:

foreach (string item in sArray)
{
   item = "Some assignment.\r\n";
}

Here's a rough approximation of what the compiler does with this: 这是编译器对此做的粗略近似

using (var enumerator = sArray.GetEnumerator())
{
    string item;
    while (enumerator.MoveNext())
    {
        item = enumerator.Current;

        // Your code gets put here
    }
}

The IEnumerator<T>.Current property is read-only, but that's not actually relevant here, as you are attempting to assign the local item variable to a new value. IEnumerator<T>.Current属性是只读的,但这里实际上并不相关,因为您尝试将本地item变量分配给新值。 The compile-time check preventing you from doing so is in place basically to protect you from doing something that isn't going to work like you expect (ie, changing a local variable and having no effect on the underlying collection/sequence). 编译时检查阻止你这样做基本上是为了保护你不要做一些像你期望的那样无法工作的事情(即,更改局部变量并且对底层集合/序列没有影响)。

If you want to modify the internals of an indexed collection such as a string[] while enumerating, the traditional way is to use a for loop instead of a foreach : 如果要在枚举时修改索引集合(如string[]的内部),则传统方法是使用for循环而不是foreach

for (int i = 0; i < sArray.Length; ++i)
{
    sArray[i] = "Some assignment.\r\n";
}

The foreach loop is designed to iterate through objects in a collection, not to assign things- it's simply design of the language. foreach循环旨在迭代集合中的对象,而不是分配东西 - 它只是语言的设计。

Also, from MSDN: 另外,来自MSDN:

"This error occurs when an assignment to variable occurs in a read- only context. Read-only contexts include foreach iteration variables, using variables, and fixed variables. To resolve this error, avoid assignments to a statement variable in using blocks, foreach statements, and fixed statements." “在只读上下文中对变量赋值时会发生此错误。只读上下文包括foreach迭代变量,使用变量和固定变量。要解决此错误,请避免在使用块,foreach语句中赋值给语句变量和固定的陈述。“

The foreach keyword just enumerates IEnumerable instances (getting an IEnumerator instances by calling the GetEnumerator() method). foreach关键字只枚举IEnumerable实例(通过调用GetEnumerator()方法获取IEnumerator实例)。 IEnumerator is read-only, therefore values can't be changed using IEnumerator =can't be changed using the foreach context. IEnumerator是只读的,因此使用IEnumerator =无法更改值,无法使用foreach上下文进行更改。

Because the language specification says so. 因为语言规范是这样说的。

But seriously, not all sequences are arrays or things that can be logically modified or written to. 但严重的是,并非所有序列都是可以逻辑修改或写入的数组或事物。 For instance: 例如:

foreach (var i in Enumerable.Range(1, 100)) {
   // modification of `i` will not make much sense here.
}

While it would've been technically possible to have i = something; 虽然技术上可能有i = something; modify a local variable, it can be misleading (you may think it really changes something under the hood and it wouldn't be the case). 修改一个局部变量,它可能会产生误导(你可能认为它真的改变了一些东西,但事实并非如此)。

To support these kind of sequences, IEnumerable<T> doesn't require a set accessor for its Current property, making it read-only. 为了支持这些序列, IEnumerable<T>不需要为其Current属性set一个访问器,使其成为只读。 Thus, foreach cannot modify the underlying collection (if one exists) using the Current property. 因此, foreach不能使用Current属性修改底层集合(如果存在)。

Because you can't use a foreach loop to modify an array you're looping through. 因为你不能使用foreach循环来修改你正在循环的数组。 The loop iterates through the array, so if you try to modify what it's iterating through then unexpected behavior may occur. 循环遍历数组,因此如果您尝试修改它迭代的内容,则可能会发生意外行为。 Furthermore, as Darin and DMan have pointed out, you're iterating through an IEnumerable which is itself read-only. 此外,正如Darin和DMan指出的那样,你正在迭代IEnumerable ,它本身就是只读的。

PHP makes a copy of the array in its foreach loop and iterates through that copy, unless you use references, in which case you'll modify the array itself. PHP在其foreach循环中生成数组的副本并遍历该副本,除非您使用引用,在这种情况下,您将修改数组本身。

因为IEnumerable是只读的。

In general, if you're trying to do this, you need to think long and hard about your design, because you're probably not using the best construction. 一般来说,如果你想要这样做,你需要长时间地思考你的设计,因为你可能没有使用最好的结构。 In this case, the best answer would probably be 在这种情况下,最好的答案可能是

string[] sArray = Enumerable.Repeat("Some assignment.\r\n", 5).ToArray();

Higher level constructions are almost always usable instead of this kind of loop in C#. 更高级别的构造几乎总是可用,而不是C#中的这种循环。 (And C++, but that's a whole other topic) (和C ++,但这是一个完整的其他主题)

You cannot modify an array that you are foreach'ing through. 你不能修改你正在经历的数组。 Use The following code instead: 请改用以下代码:

string[] sArray = new string[5]; 

for (int i=0;i<sArray.Length;i++)
{
    item[i] = "Some Assignment.\r\n";
}

The foreach is designed to interate through the array once, without repeating or skipping (though you can skip some action within the foreach construct by using the continue keyword). foreach旨在通过数组进行一次交互,而不重复或跳过(尽管您可以使用continue关键字跳过foreach结构中的某些操作)。 If you want to modify the current item, consider using a for loop instead. 如果要修改当前项,请考虑使用for循环。

You cannot modify a list that is being looped through via a "ForEach". 您无法通过“ForEach”修改正在循环的列表。

The best option is to simply create a temporary list to store the items you wish to use. 最好的选择是简单地创建一个临时列表来存储您想要使用的项目。

It would be perfectly possible to let it be altered. 完全可以改变它。 However, what does this then mean? 但是,这意味着什么呢? It would read like the underlying enumeration was modified, which it isn't (it would be possible to allow that too, but that has its own downsides). 它会读取基础枚举被修改,但它不是(也可以允许它,但它有自己的缺点)。

So you'd have code that people would naturally read as indicating something other than what has actually happened. 因此,您将拥有人们自然会阅读的代码,以表示除了实际发生的事情之外的其他内容。 Considering that the purpose of a computer language is primarily to be understood by people (compilers deal with the balance being set against them, unless you use assembly, machine code, or the appropriately named Brainf**k) this would indicate a flaw in the language. 考虑到计算机语言的目的主要是由人们理解(编译器处理针对它们设置的平衡,除非你使用汇编,机器代码或适当命名的Brainf ** k),这将表明存在一个缺陷。语言。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM