问题描述
考虑下面的C#code。
字符串[]字符串数组=新的字符串[10];
的foreach(字符串s中的字符串数组)
S =一个新的字符串; //编译器错误 - 不能分配给foreach迭代变量
现在考虑下面的有效 C ++ / CLI code。
阵列和LT;字符串^> ^字符串数组= gcnew阵列<字符串^>(10);
每一个(在字符串数组字符串^%S)
S =一个新的字符串;
在的foreach
是用于数组类型,编译器将其转换为正常为
循环。这种实现是一样的C#和C ++ / CLI。所以我想如果C ++ / CLI可以实现这一点,为什么不为C#编译器?
此错误是有道理的,当类型不是一个数组的foreach
将汇编成的GetEnumerator
通话和使用普查员进行迭代。但我认为这可以允许数组类型。
有什么想法?
作为一个侧面说明,下面是一个有效的C ++ / CLI code太多,但不会产生预期的结果。
名单,其中,串^> ^ StringList的= gcnew名单,其中,串^>(10);
每一个(在StringList的字符串^%S)
S =一个新的字符串; //我想这应该是由编译器pvented $ P $,因为它是没有意义的。
似乎有这里三个不同的问题:
- 为什么C ++允许您分配给
每个
迭代变量? - 为什么不是C#?
- 为什么在C ++和C#编译器的行为不同?
这些问题的答案相当简单:
-
由于C ++的团队决定不明确的不允许的它,并在技术上迭代变量仅仅是一个局部变量 - 它没有得到特殊待遇
-
由于C#团队的没有的决定禁止的,因为(最有可能),他们认为这会导致错误或不正确的code。分配到的任意的循环变量通常被视为code气味。
-
由于C ++的团队和C#团队是不同的球队。 C ++一直是一种语言,它允许你搬起石头砸自己的脚,如果你选择,并且去,至于交给你了装满子弹的枪。 C#中会经常尝试执行正确的code的规则。
有可能实际上是在这里另外一个问题,那就是:
- 为什么C#编译
的foreach
到为
如果不允许转让?或者,反过来 - 为什么不允许这样做,如果这是它得到反正编译
实际上有两个答案,这一个:
-
由于它的速度更快。
的foreach
运行在的IEnumerable
,这需要一个新的的IEnumerator
类被实例化。数组类型由编译器可识别的特殊类型,因此,如果编译器已经知道了的IEnumerable
实际上是一个阵列
,然后将其编译成索引访问,相反,这是便宜多了。这一点表现的调整是一个简单的实施细节,但是,它不是在说明的一部分,如果你能写code依赖于具体实现,C#团队将无法在以后更改,落实不打破现有的code。他们肯定要避免这样的情况。
-
由于它实际上并不重要的方法之一可能会认为它。如果你能做到的分配在C#中,你会不会实际上是修改阵列,最初举行的数组东西局部变量只是内容。这又落入下的类别,难以写不正确code - 如果结构的没有的,您可以赋给变量,一些程序员可能会认为这样的实际上改变集合的,这将是错误的。
我觉得应该解释一下pretty的好。
Consider the following C# code.
string[] stringArray = new string[10];
foreach (string s in stringArray)
s = "a new string"; // Compiler error - Can't assign to foreach iteration variable
Now consider the following valid C++/CLI code.
array<String^>^ stringArray = gcnew array<String^>(10);
for each(String^% s in stringArray)
s = "a new string";
When foreach
is used with array type, compiler translates it into normal for
loop. This implementation is same for C# and C++/CLI. So I wonder if C++/CLI can allow this, why not for C# compiler?
This error makes sense when the type is not an array as foreach
will be compiled into GetEnumerator
call and use the enumerator for iteration. But I think it can be allowed for array types.
Any thoughts?
As a side note, the following is a valid C++/CLI code too but will not produce the expected result.
List<String^>^ stringList = gcnew List<String^>(10);
for each(String^% s in stringList)
s = "a new string"; // I think this should be prevented by compiler as it makes no sense.
There seem to be three different questions here:
- Why does C++ allow you to assign to a
for each
iteration variable? - Why doesn't C#?
- Why do the C++ and C# compilers behave differently?
The answers are fairly straightforward:
Because the C++ team didn't decide to explicitly disallow it, and technically the iteration variable is just a local variable - it doesn't get special treatment.
Because the C# team did decide to disallow it, because (most likely) they believe it would lead to bugs or incorrect code. Assigning to any loop variable is commonly considered a code smell.
Because the C++ team and the C# team are different teams. C++ has always been a language that allows you to shoot yourself in the foot, if you so choose, and goes so far as to hand you the loaded gun. C# will often try to enforce "correct code" rules.
There might actually be another question here, which is:
- Why would C# compile a
foreach
into afor
if it doesn't allow assignment? Or, the converse - why doesn't allow this if that's how it gets compiled anyway?
There are actually two answers to this one:
Because it's faster.
foreach
operates onIEnumerable
, which requires a newIEnumerator
class to be instantiated. Array types are special types recognized by the compiler, so if the compiler already knows that theIEnumerable
is actually anArray
, then it compiles down to indexed access instead, which is much cheaper.This little performance tweak is simply an implementation detail, however; it is not part of the specification, and if you were able to write code that depends on the specific implementation, the C# team would be unable to change that implementation later without breaking existing code. They would certainly want to avoid such a situation.
Because it doesn't actually matter the way one might think it does. If you could do the assignment in C#, you would not actually be modifying the array, only the contents of the local variable that initially held something from the array. This, again, falls under the category of "make it difficult to write incorrect code" - if the construct did allow you to assign to the variable, some programmers might think that this would actually change the collection, which would be false.
I think that should explain it pretty well.
这篇关于更改C#和C ++ / CLI的foreach迭代变量,并实现差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!