我怎样才能(如果可能的话)在C#for
循环中初始化不同类型的多个变量?例如:
for (MyClass i = 0, int j = 1; j<3; j++,i++)
答案 0 :(得分:77)
无法做到。在循环之前放置一个声明:
MyClass i = 0;
for (int j = 1; j < 3; j++, i++)
或者对称性,两者都是:
MyClass i = 0;
int j = 1;
for (; j < 3; j++, i++)
其中一个变量也可能比另一个变量更为主要变量。在这种情况下,让一个人成为循环变量可能比较简洁,并且单独处理另一个变量,如下所示:
MyClass i = 0;
for (int j = 0; j < 3; j++)
{
...
i++;
}
请注意,如果i
和j
属于同一类型,那么您可以在for循环中声明它们:
for (int i = 0, j = 1; j < 3; j++, i++)
答案 1 :(得分:34)
当然可以做到。只需使用动态关键字:
public static void Main(string[] args) {
for (dynamic x = 0, y = new MyClass { a = 20, b = 30 }; x < 100; x++, y.a++, y.b--) {
Console.Write("X=" + x + " (" + x.GetType() + "\n" +
"Y.a=" + y.a + ",Y.b=" + y.b + " (" + y.GetType() + "\n");
}
}
class MyClass {
public int a = 0, b = 0;
}
祝你有美好的一天!
答案 2 :(得分:15)
是的,可以做到。您可以在for语句中初始化不同类型的变量,但不能在for语句中声明不同类型的变量。为了在for语句中初始化不同类型的变量,必须在for循环之前声明所有类型。例如:
int xx;
string yy;
for(xx=0, yy=""; xx<10; xx++)
{
....
}
[编辑]添加更多信息以保证完整性。这超出了OP的要求,但可能对其他人有所帮助。 在for循环中初始化相同类型的变量很简单,只需用逗号分隔初始化即可。您还可以在第三部分中更改多个变量。你不能在第二个比较部分中有多个逗号分隔的部分,但你可以使用&amp;&amp; ||而且!根据多个变量制作复杂的布尔部分。
for(int i=0, j=0, k=99; i<10 && k<200; i++, j++, k += 2)
但是,制作一个非常复杂的for语句并不难理解正在发生的事情并不是一个好习惯。
答案 3 :(得分:8)
有害吗?
是的,非常如此。语言分析器具有两个重要职责。一个是每个人都熟悉的工作,将文本转换为可执行程序。但非常重要的是,它可以检测无效程序并为程序员生成有意义的诊断,以便他可以修复他的代码。
在非常基础的层面上,语言解析器区分声明,语句和表达式。大括号语言会混淆这种区别,您可以将任何表达式转换为语句,只需在其后面加一个分号即可。在某些情况下,在语句中接受声明,for(;;)语句就是一个很好的例子。最明显的是,这种语法在C或C ++语言中是完全可以接受的:
int x = 42;
x;
这不是一件好事,这是无意义的代码。 C#语言提高了标准,它将拒绝这一点。但不是:
int x = 42;
x++;
添加到语言解析器的特殊规则接受此规则。
任何卷括号语言都不会接受将声明转换为表达式。那种方式就是疯狂,龙在地图的尽头,船只从边缘掉下来,没有留下好的信息报告。逗号运算符要求左手和右手操作数为表达式。宣言不是表达,故事的结尾。
答案 4 :(得分:5)
我通常将声明置于循环之前,并使用其他花括号来限制声明的范围:
{ //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 ) )
{
//...
}
}
答案 5 :(得分:4)
从C#7.0开始,您可以使用解构语法:
for (var (i, j) = (0, (MyClass) 1); j < 3; i++, j++)
{
Console.WriteLine(i);
}
我假设您已经定义了MyClass的所有重载
internal class MyClass
{
private MyClass(int i)
{
Value = i;
}
private int Value { get; set; }
public static explicit operator MyClass(int i) => new MyClass(i);
public static implicit operator int(MyClass d) => d.Value;
public static MyClass operator ++(MyClass a)
{
a.Value++;
return a;
}
}
答案 6 :(得分:2)
从C#7开始,使用元组:
for (var foo = (i:new MyClass(0), j:1); foo.j < 3; foo.i++, foo.j++)) { … }
答案 7 :(得分:1)
for (initializer; condition; iterator)
{
//body
}
初始化程序部分设置初始条件。在进入循环之前,本节中的语句只运行一次。该部分只能包含以下两个选项之一。
1)本地循环变量的声明和初始化。该变量是循环的局部变量,无法从循环外部访问。
2)以下列表中的零个或多个语句表达式,以逗号分隔:
作业声明;
调用方法;
前缀或后缀增量表达式,例如++ i或i ++;
前缀或后缀递减表达式,例如--i或i - ;
使用new创建对象;
等待表达;
正如我们所知,编译器的设计并不是为了接受我们期望的方式。所以上面是在for循环中编写 初始化部分 之前必须遵循的规则。
答案 8 :(得分:0)
我认为你不能在for循环中定义多个类型。 仅用于(int i = 0,j = 3; j <7; j ++,i ++)
答案 9 :(得分:0)
您无法在循环结构中定义多个变量。请尝试以下代码:
选项1:在循环之前声明的一个变量,每次迭代手动递增一次。
MyClass i = 0;
for (int j = 1; j<3; j++)
{
//do stuff
i++
}
选项2:两个变量在for循环之前设置,一个在循环结构中递增,其他变量在循环中手动设置。
MyClass i = 0;
int j = 1
for (; j<3; j++)
{
//do stuff
i++
}
选项3:两个变量都在for循环结构之前设置,并且两个变量在循环中递增,让循环只检查一个条件,此时你可以只做一个while loop。
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++
}
答案 10 :(得分:0)
这不是我的专长,但这是我对这个主题的集思广益:
在programmimng语言理论中,必须定义语言的语法而不含糊。我不能详细介绍它,因为我研究这些主题已有几年了。但是你可以检查Backus-Naur Form这是一种用来描述语言“语法”的符号技巧。这是我唯一熟悉的。
因此在解析代码时使用此描述。并且您的解析器必须能够将代码的每个部分与语法的“规则”相关联。你可以看到C#语法here。它有点类似的形式。
(1)看一下for语句的语法
for-statement:
for(for-initializer;for-condition;for-iterator)
embedded-statement
然后for-initializer语法
for-initializer:
local-variable-declaration
statement-expression-list
请注意,statement-expression-list仅用于for循环。它也是一个逗号分隔的语句表达式列表。
我会在这里留下一些中间步骤,但你可以按照语法让自己对这个想法更加自在。
Here是一套很好的基本幻灯片,它展示了即使使用简单的语法也能让事情变得复杂。
(2)我们在1中观察到的是我们可以为for循环的初始化器部分添加什么。我们知道为什么你的建议不起作用。为了成为赏金猎人,让我们分析一下这种设计选择的原因。
首先,这是一个设计选择。您可以设计或找到允许该语言的语言。应该可以通过改变语法来实现,但是可能需要进行一些语法上的修改。这就是原因;
如果您要放置多个声明语句,您可能希望有类似声明列表的内容。而你将要用于分离器,你可能不想使用;因为分号用于分隔for循环的部分。所以,你总是可以使用逗号,但是如果你使用逗号,那么声明列表规则只能用于for循环,因为在你的代码中使用逗号分隔的声明会很困惑。
其次,这有什么问题?如果你问我,我也没有看到任何错误。如果他们设计了应该有效的语言。 (我不是说我刚刚制作的草图是100%正确的,它只能用作头脑风暴会议的起点。)
然后,他们为什么选择不这样做?是什么促使他们避免这种情况?
经过所有这些和许多其他考虑后,
......还有更多像这样的问题,必须谨慎行事。通过查看这些问题及其分析,我会说编译器设计者的设计选择几乎是最可接受的方法。
答案 11 :(得分:0)
没有理由不在带内初始化备用索引器。它使环境远离无用的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
}
答案 12 :(得分:0)
让我们玩得开心。我会让你决定是否应该在任何地方使用它......:P
在不使用动态关键字的情况下,可以(间接)声明和初始化for循环初始化程序中所需的不同类型的变量。只需为索引变量使用自定义结构。
for(var i = new I1<MyClass>(0, 1); i < 3; i++, i.a++) {
MyClass myClass = i.a;
}
重载运算符意味着你可以在任何地方使用“i”。要获得干净的语法,请使用0:
进行初始化for(I1<float> i = 0; i < array.Length; i++) {
i.a += array[i]; // accumulate a float value
}
一些更愚蠢的例子:
// Three variables
for(I3<object, string, int> i = 0; i < 100; i++) {
i.a = new object();
i.b = "This is index " + i;
i.c = 100 - i;
}
// A class
for(var i = new I1<SomeClass>(0, new SomeClass()); i < 20; i += 2) {
i.a.someVar1 = "We can have even more variables in here! Woot!";
i.a.DoSomething(i);
}
// An array
for(var i = new I1<string[]>(0, new[] { "Hi", "Mom" }); i < 10; i++) {
for(int j = 0; j < i.a.Length; j++) {
Log(i.a[j]);
}
}
以下是结构。它们确实有效但未经过彻底测试,因此可能存在错误:
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;
}
}