在C#中多次初始化'for'循环

我怎么能(如果有可能的话)在C# for循环中初始化多个不同types的variables? 例:

 for (MyClass i = 0, int j = 1; j<3; j++,i++) 

这是不能做到的。 将其中一个声明放在循环之前:

 MyClass i = 0; for (int j = 1; j < 3; j++, i++) 

或者为了对称,他们都是:

 MyClass i = 0; int j = 1; for (; j < 3; j++, i++) 

其中一个variables可能比另一个更重要。 在这种情况下,让一个variables变成循环variables可能更为简单,另一个单独处理,就像这样:

 MyClass i = 0; for (int j = 0; j < 3; j++) { ... i++; } 

请注意,如果ij是相同的types,那么你可以在for循环中声明它们:

 for (int i = 0, j = 1; j < 3; j++, i++) 

当然可以做到。 只需使用dynamic关键字:

 public static void Main(string[] args) { for (dynamic x = 0, y = new MyClass { a = 20, b = 30 }; x < 100; x++, y.a++, yb--) { Console.Write("X=" + x + " (" + x.GetType() + "\n" + "Ya=" + ya + ",Yb=" + yb + " (" + y.GetType() + "\n"); } } class MyClass { public int a = 0, b = 0; } 

祝你有美好的一天!

是的,可以做到。 您可以在for语句中初始化不同types的variables,但不能在for语句中声明不同types的variables。 为了在for语句中初始化不同types的variables,你必须在for循环之前声明所有的types。 例如:

 int xx; string yy; for(xx=0, yy=""; xx<10; xx++) { .... } 

[编辑]添加更多信息的完整性。 这超出了OP所要求的,但可能对其他人有帮助。 在for循环中初始化相同types的variables非常简单,只需用逗号分隔初始化即可。 您也可以在第三部分中更改多个variables。 在第二个比较部分中,不能有多个逗号分隔的部分,但是可以使用&& || 和! 基于多个variables创build一个复杂的布尔部分。

 for(int i=0, j=0, k=99; i<10 && k<200; i++, j++, k += 2) 

但是,要做出一个如此复杂的陈述,以至于很难理解正在发生的事情,这不是一个好习惯。

有害吗?

是的,非常非常。 语言parsing器有两个重要的职责。 一个是大家熟悉的工作,将文本转换成可执行程序。 但是非常重要的一点是,它可以检测到一个无效的程序,并为程序员生成一个有意义的诊断信息,以便修复他的代码。

在非常基本的层面上,语言分析器区分声明语句expression式 。 花括号语言对这种区别做了模糊处理,你可以把任何expression式转换成一个语句,只需在它后面加一个分号即可。 在某些情况下,在声明中接受声明,for(;;)语句就是一个很好的例子。 最明显的是,这种语法在C或C ++语言中是完全可以接受的:

 int x = 42; x; 

这不是一件好事,这是无稽之谈。 C#语言提高了吧,它会拒绝这一点。 但不是:

 int x = 42; x++; 

添加到语言分析器接受这个特殊的规则。

什么花括号语言都不能接受的是把一个声明转换成一个expression式。 这种方式是疯狂的,在地图的尽头的龙,船掉下来没有留下好消息报告。 逗号运算符要求左边和右边的操作数是expression式。 宣言不是一个expression,故事的结尾。

我通常在循环之前放置声明,并使用额外的大括号来限制声明的范围:

 { //limit the scope: i, count, iDivisibleBy2, iDivisibleBy3, iDivisibleBy5 int i = 0, count = 100; bool iDivisibleBy2 = true, iDivisibleBy3 = true, iDivisibleBy5 = true; for( ; i < count; ++i, iDivisibleBy2 = (i % 2 == 0), iDivisibleBy3 = ( i % 3 == 0 ), iDivisibleBy5 = ( i % 5 == 0 ) ) { //... } } 
 for (initializer; condition; iterator) { body } 

初始化部分设置初始条件。 在进入循环之前,本节中的语句只运行一次。 该部分只能包含以下两个选项之一。

1)本地循环variables的声明和初始化。 该variables是循环的本地variables,不能从循环外部访问。

2)以下列表中的零个或多个语句expression式,用逗号分隔。

  assignment statement invocation of a method prefix or postfix increment expression, such as ++i or i++ prefix or postfix decrement expression, such as --i or i-- creation of an object by using new await expression 

正如我们所知道的,编译器的devise并不是我们所期望的。 所以上面是在for循环中写入一个初始化部分之前必须遵循的规则。

http://msdn.microsoft.com/en-us/library/ch45axte.aspx

我不认为你可以在for循环中定义多个types。 仅适用于(int i = 0,j = 3; j <7; j ++,i ++)

您不能在循环结构中定义多个variables。 试试下面的代码:

选项1:在循环之前声明一个variables,并在循环中手动递增一次。

 MyClass i = 0; for (int j = 1; j<3; j++) { //do stuff i++ } 

选项2:两个variables在for循环之前设置,一个在循环结构中递增,另一个在手动循环中递增。

 MyClass i = 0; int j = 1 for (; j<3; j++) { //do stuff i++ } 

选项3:这两个variables都是在循环结构之前设置的,而且这两个variables在循环中都是递增的,只留下循环来检查一个条件,在这一点上你可以做一个while循环。

 MyClass i = 0; int j = 1 for (; j<3) { //do stuff j++ i++ } 

选项4:写作一个while循环

 MyClass i = 0; int j = 1 while (j<3) { //do stuff j++ i++ } 

这不是我的专长,但这是我关于这个话题的头脑风暴:

在编程语言理论中,语言的语法必须没有歧义地定义。 自从我研究这些主题以来已有数年的时间了,所以我不能深入细节。 但是你可以检查Backus-Naur Form这个表示技巧的语言来描述语言的“语法”。 这是我所熟悉的唯一。

所以在parsing代码时使用了这个描述。 你的parsing器必须能够把你的代码的每一部分与语法的“规则”联系起来。 你可以在这里看到C#的语法。 它有点类似的forms。

(1)看一看for语句的语法

 for-statement: for(for-initializer;for-condition;for-iterator) embedded-statement 

然后用于初始化语法

 for-initializer: local-variable-declaration statement-expression-list 

请注意,statement-expression-list仅用于for循环。 它也是逗号分隔的语句expression式列表。

我会在这里留下一些中间步骤,但是你可以按照语法来让自己更适应这个想法。

这里有一个很好的基本幻灯片集,演示了如何使用一个简单的语法就可以得到多么复杂的东西。

(2)我们在1中观察到的是什么可以为for循环的初始化部分。 而且我们知道为什么你的build议不起作用。 作为赏金猎人,让我们分析一下这个deviseselect的原因吧。

首先, 这是一个deviseselect 。 您可以devise或find允许的语言。 应该可以通过改变语法,但是一些语法上的改变可能是必要的。 这是为什么;

如果你打算把多个声明语句,你可能想要像声明列表。 而你将用于分隔符,你可能不想使用; 因为使用分号分隔for循环的部分。 所以,你总是可以使用逗号,但是如果使用逗号,那么声明列表规则只能在for循环中使用,因为在你的代码中使用逗号分隔的声明会令人困惑。

其次,那有什么问题? 如果你问我,我也没有看到任何错误。 如果他们devise了它应该工作的语言。 (我不是说我刚才所画的草图是100%正确的,只能作为头脑风暴会议的起点。)

那么,他们为什么select不呢? 是什么促使他们避免这种情况?

  • 你把这个规则加到你的语法中会引入多less复杂性?
  • 你是否还考虑要添加多less额外的规则才能使语言毫不含糊?
  • 你知道已经存在的规则有多复杂吗?
  • 多less工作量增加到你的parsing器,然后编译器?

经过所有这些和许多其他考虑,

  • 你为语言的可用性,可读性增加了多less?
  • 或者你甚至失去了一些可读性?
  • 你有没有想过,程序员需要这些types的循环?
  • 即使他们经常需要,你是否应该鼓励或劝阻他们这种types的编码?

…还有更多这样的问题,一定要慎重。 通过查看这些问题及其分析,我会说编译器devise者的deviseselect几乎是最可接受的方法。

几乎没有理由没有在带内初始化一个备用索引器。 它保持环境清晰无用的var分配。

 for (int x=0,y = 0; x < 100; x++) { if (true) { y++; } // ... use y as a conditional indexer // ... x is always the loop indexer // ... no overflows } 

让我们玩得开心点 我将留给你决定是否应该在任何地方使用这个…:P

在for循环初始化程序中,可以(间接)声明和初始化任意多个variables,而不使用dynamic关键字。 只需使用一个自定义结构为您的索引variables。

 for(var i = new I1<MyClass>(0, 1); i < 3; i++, i.a++) { MyClass myClass = ia; } 

重载的运算符意味着你可以像“int”一样使用“i”。 对于干净的语法,用0初始化:

 for(I1<float> i = 0; i < array.Length; i++) { ia += array[i]; // accumulate a float value } 

一些更愚蠢的例子:

 // Three variables for(I3<object, string, int> i = 0; i < 100; i++) { ia = new object(); ib = "This is index " + i; ic = 100 - i; } // A class for(var i = new I1<SomeClass>(0, new SomeClass()); i < 20; i += 2) { iasomeVar1 = "We can have even more variables in here! Woot!"; iaDoSomething(i); } // An array for(var i = new I1<string[]>(0, new[] { "Hi", "Mom" }); i < 10; i++) { for(int j = 0; j < iaLength; j++) { Log(ia[j]); } } 

这里是结构。 他们工作,但没有得到彻底的testing,所以可能有错误:

 public struct I1<T> { public int index; public T a; public I1(int index) { this.index = index; this.a = default(T); } public I1(int index, T a) { this.index = index; this.a = a; } public override bool Equals(object obj) { if(!(obj is I1<T>)) return false; I1<T> other = (I1<T>)obj; return index == other.index && EqualityComparer<T>.Default.Equals(a, other.a); } public override int GetHashCode() { int hash = 17; hash = hash * 29 + index.GetHashCode(); if(typeof(T).IsValueType && !object.ReferenceEquals(a, null)) hash = hash * 29 + a.GetHashCode(); return hash; } public override string ToString() { return index.ToString(); } public static implicit operator I1<T>(int other) { return new I1<T>(other); } public static implicit operator int(I1<T> other) { return other.index; } // Unary operators public static int operator +(I1<T> a) { return +a.index; } public static int operator -(I1<T> a) { return -a.index; } public static int operator ~(I1<T> a) { return ~a.index; } public static I1<T> operator ++(I1<T> a) { a.index++; return a; } public static I1<T> operator --(I1<T> a) { a.index--; return a; } // Binary operators public static I1<T> operator +(I1<T> a, int b) { a.index += b; return a; } public static I1<T> operator +(int a, I1<T> b) { b.index += a; return b; } public static I1<T> operator -(I1<T> a, int b) { a.index -= b; return a; } public static I1<T> operator -(int a, I1<T> b) { b.index = a - b.index; return b; } public static I1<T> operator *(I1<T> a, int b) { a.index *= b; return a; } public static I1<T> operator *(int a, I1<T> b) { b.index *= a; return b; } public static I1<T> operator /(I1<T> a, int b) { a.index /= b; return a; } public static I1<T> operator /(int a, I1<T> b) { b.index = a / b.index; return b; } public static I1<T> operator %(I1<T> a, int b) { a.index %= b; return a; } public static I1<T> operator %(int a, I1<T> b) { b.index = a % b.index; return b; } public static I1<T> operator &(I1<T> a, int b) { a.index &= b; return a; } public static I1<T> operator &(int a, I1<T> b) { b.index = a & b.index; return b; } public static I1<T> operator |(I1<T> a, int b) { a.index |= b; return a; } public static I1<T> operator |(int a, I1<T> b) { b.index = a | b.index; return b; } public static I1<T> operator ^(I1<T> a, int b) { a.index ^= b; return a; } public static I1<T> operator ^(int a, I1<T> b) { b.index = a ^ b.index; return b; } public static I1<T> operator <<(I1<T> a, int b) { a.index <<= b; return a; } public static I1<T> operator >>(I1<T> a, int b) { a.index >>= b; return a; } // Comparison operators public static bool operator ==(I1<T> a, int b) { return a.index == b; } public static bool operator ==(int a, I1<T> b) { return a == b.index; } public static bool operator !=(I1<T> a, int b) { return a.index != b; } public static bool operator !=(int a, I1<T> b) { return a != b.index; } public static bool operator <(I1<T> a, int b) { return a.index < b; } public static bool operator <(int a, I1<T> b) { return a < b.index; } public static bool operator >(I1<T> a, int b) { return a.index > b; } public static bool operator >(int a, I1<T> b) { return a > b.index; } public static bool operator <=(I1<T> a, int b) { return a.index <= b; } public static bool operator <=(int a, I1<T> b) { return a <= b.index; } public static bool operator >=(I1<T> a, int b) { return a.index >= b; } public static bool operator >=(int a, I1<T> b) { return a >= b.index; } } public struct I2<T1, T2> { public int index; public T1 a; public T2 b; public I2(int index) { this.index = index; this.a = default(T1); this.b = default(T2); } public I2(int index, T1 a) { this.index = index; this.a = a; this.b = default(T2); } public I2(int index, T1 a, T2 b) { this.index = index; this.a = a; this.b = b; } public override bool Equals(object obj) { if(!(obj is I2<T1, T2>)) return false; I2<T1, T2> other = (I2<T1, T2>)obj; return index == other.index && EqualityComparer<T1>.Default.Equals(a, other.a) && EqualityComparer<T2>.Default.Equals(b, other.b); } public override int GetHashCode() { int hash = 17; hash = hash * 29 + index.GetHashCode(); if(typeof(T1).IsValueType && !object.ReferenceEquals(a, null)) hash = hash * 29 + a.GetHashCode(); if(typeof(T2).IsValueType && !object.ReferenceEquals(b, null)) hash = hash * 29 + b.GetHashCode(); return hash; } public override string ToString() { return index.ToString(); } public static implicit operator I2<T1, T2>(int other) { return new I2<T1, T2>(other); } public static implicit operator int(I2<T1, T2> other) { return other.index; } // Unary operators public static int operator +(I2<T1, T2> a) { return +a.index; } public static int operator -(I2<T1, T2> a) { return -a.index; } public static int operator ~(I2<T1, T2> a) { return ~a.index; } public static I2<T1, T2> operator ++(I2<T1, T2> a) { a.index++; return a; } public static I2<T1, T2> operator --(I2<T1, T2> a) { a.index--; return a; } // Binary operators public static I2<T1, T2> operator +(I2<T1, T2> a, int b) { a.index += b; return a; } public static I2<T1, T2> operator +(int a, I2<T1, T2> b) { b.index += a; return b; } public static I2<T1, T2> operator -(I2<T1, T2> a, int b) { a.index -= b; return a; } public static I2<T1, T2> operator -(int a, I2<T1, T2> b) { b.index = a - b.index; return b; } public static I2<T1, T2> operator *(I2<T1, T2> a, int b) { a.index *= b; return a; } public static I2<T1, T2> operator *(int a, I2<T1, T2> b) { b.index *= a; return b; } public static I2<T1, T2> operator /(I2<T1, T2> a, int b) { a.index /= b; return a; } public static I2<T1, T2> operator /(int a, I2<T1, T2> b) { b.index = a / b.index; return b; } public static I2<T1, T2> operator %(I2<T1, T2> a, int b) { a.index %= b; return a; } public static I2<T1, T2> operator %(int a, I2<T1, T2> b) { b.index = a % b.index; return b; } public static I2<T1, T2> operator &(I2<T1, T2> a, int b) { a.index &= b; return a; } public static I2<T1, T2> operator &(int a, I2<T1, T2> b) { b.index = a & b.index; return b; } public static I2<T1, T2> operator |(I2<T1, T2> a, int b) { a.index |= b; return a; } public static I2<T1, T2> operator |(int a, I2<T1, T2> b) { b.index = a | b.index; return b; } public static I2<T1, T2> operator ^(I2<T1, T2> a, int b) { a.index ^= b; return a; } public static I2<T1, T2> operator ^(int a, I2<T1, T2> b) { b.index = a ^ b.index; return b; } public static I2<T1, T2> operator <<(I2<T1, T2> a, int b) { a.index <<= b; return a; } public static I2<T1, T2> operator >>(I2<T1, T2> a, int b) { a.index >>= b; return a; } // Comparison operators public static bool operator ==(I2<T1, T2> a, int b) { return a.index == b; } public static bool operator ==(int a, I2<T1, T2> b) { return a == b.index; } public static bool operator !=(I2<T1, T2> a, int b) { return a.index != b; } public static bool operator !=(int a, I2<T1, T2> b) { return a != b.index; } public static bool operator <(I2<T1, T2> a, int b) { return a.index < b; } public static bool operator <(int a, I2<T1, T2> b) { return a < b.index; } public static bool operator >(I2<T1, T2> a, int b) { return a.index > b; } public static bool operator >(int a, I2<T1, T2> b) { return a > b.index; } public static bool operator <=(I2<T1, T2> a, int b) { return a.index <= b; } public static bool operator <=(int a, I2<T1, T2> b) { return a <= b.index; } public static bool operator >=(I2<T1, T2> a, int b) { return a.index >= b; } public static bool operator >=(int a, I2<T1, T2> b) { return a >= b.index; } } public struct I3<T1, T2, T3> { public int index; public T1 a; public T2 b; public T3 c; public I3(int index) { this.index = index; this.a = default(T1); this.b = default(T2); this.c = default(T3); } public I3(int index, T1 a) { this.index = index; this.a = a; this.b = default(T2); this.c = default(T3); } public I3(int index, T1 a, T2 b) { this.index = index; this.a = a; this.b = b; this.c = default(T3); } public I3(int index, T1 a, T2 b, T3 c) { this.index = index; this.a = a; this.b = b; this.c = c; } public override bool Equals(object obj) { if(!(obj is I3<T1, T2, T3>)) return false; I3<T1, T2, T3> other = (I3<T1, T2, T3>)obj; return index == other.index && EqualityComparer<T1>.Default.Equals(a, other.a) && EqualityComparer<T2>.Default.Equals(b, other.b) && EqualityComparer<T3>.Default.Equals(c, other.c); } public override int GetHashCode() { int hash = 17; hash = hash * 29 + index.GetHashCode(); if(typeof(T1).IsValueType && !object.ReferenceEquals(a, null)) hash = hash * 29 + a.GetHashCode(); if(typeof(T2).IsValueType && !object.ReferenceEquals(b, null)) hash = hash * 29 + b.GetHashCode(); if(typeof(T3).IsValueType && !object.ReferenceEquals(c, null)) hash = hash * 29 + c.GetHashCode(); return hash; } public override string ToString() { return index.ToString(); } public static implicit operator I3<T1, T2, T3>(int other) { return new I3<T1, T2, T3>(other); } public static implicit operator int(I3<T1, T2, T3> other) { return other.index; } // Unary operators public static int operator +(I3<T1, T2, T3> a) { return +a.index; } public static int operator -(I3<T1, T2, T3> a) { return -a.index; } public static int operator ~(I3<T1, T2, T3> a) { return ~a.index; } public static I3<T1, T2, T3> operator ++(I3<T1, T2, T3> a) { a.index++; return a; } public static I3<T1, T2, T3> operator --(I3<T1, T2, T3> a) { a.index--; return a; } // Binary operators public static I3<T1, T2, T3> operator +(I3<T1, T2, T3> a, int b) { a.index += b; return a; } public static I3<T1, T2, T3> operator +(int a, I3<T1, T2, T3> b) { b.index += a; return b; } public static I3<T1, T2, T3> operator -(I3<T1, T2, T3> a, int b) { a.index -= b; return a; } public static I3<T1, T2, T3> operator -(int a, I3<T1, T2, T3> b) { b.index = a - b.index; return b; } public static I3<T1, T2, T3> operator *(I3<T1, T2, T3> a, int b) { a.index *= b; return a; } public static I3<T1, T2, T3> operator *(int a, I3<T1, T2, T3> b) { b.index *= a; return b; } public static I3<T1, T2, T3> operator /(I3<T1, T2, T3> a, int b) { a.index /= b; return a; } public static I3<T1, T2, T3> operator /(int a, I3<T1, T2, T3> b) { b.index = a / b.index; return b; } public static I3<T1, T2, T3> operator %(I3<T1, T2, T3> a, int b) { a.index %= b; return a; } public static I3<T1, T2, T3> operator %(int a, I3<T1, T2, T3> b) { b.index = a % b.index; return b; } public static I3<T1, T2, T3> operator &(I3<T1, T2, T3> a, int b) { a.index &= b; return a; } public static I3<T1, T2, T3> operator &(int a, I3<T1, T2, T3> b) { b.index = a & b.index; return b; } public static I3<T1, T2, T3> operator |(I3<T1, T2, T3> a, int b) { a.index |= b; return a; } public static I3<T1, T2, T3> operator |(int a, I3<T1, T2, T3> b) { b.index = a | b.index; return b; } public static I3<T1, T2, T3> operator ^(I3<T1, T2, T3> a, int b) { a.index ^= b; return a; } public static I3<T1, T2, T3> operator ^(int a, I3<T1, T2, T3> b) { b.index = a ^ b.index; return b; } public static I3<T1, T2, T3> operator <<(I3<T1, T2, T3> a, int b) { a.index <<= b; return a; } public static I3<T1, T2, T3> operator >>(I3<T1, T2, T3> a, int b) { a.index >>= b; return a; } // Comparison operators public static bool operator ==(I3<T1, T2, T3> a, int b) { return a.index == b; } public static bool operator ==(int a, I3<T1, T2, T3> b) { return a == b.index; } public static bool operator !=(I3<T1, T2, T3> a, int b) { return a.index != b; } public static bool operator !=(int a, I3<T1, T2, T3> b) { return a != b.index; } public static bool operator <(I3<T1, T2, T3> a, int b) { return a.index < b; } public static bool operator <(int a, I3<T1, T2, T3> b) { return a < b.index; } public static bool operator >(I3<T1, T2, T3> a, int b) { return a.index > b; } public static bool operator >(int a, I3<T1, T2, T3> b) { return a > b.index; } public static bool operator <=(I3<T1, T2, T3> a, int b) { return a.index <= b; } public static bool operator <=(int a, I3<T1, T2, T3> b) { return a <= b.index; } public static bool operator >=(I3<T1, T2, T3> a, int b) { return a.index >= b; } public static bool operator >=(int a, I3<T1, T2, T3> b) { return a >= b.index; } }