Multiple initialization in C# 'for' loop

Viewed 104553

How can I (if it is possible at all) initialize multiple variables of different type in a C# for loop? Example:

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

Since C#7.0, you can use deconstruction syntax :

for (var (i, j) = (0, (MyClass) 1); j < 3; i++, j++)
{
    Console.WriteLine(i);
}

And I'm assuming you have defined all the overloads for 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;
    }
}

As of C# 7, use a tuple:

for (var foo = (i:new MyClass(0), j:1); foo.j < 3; foo.i++, foo.j++)) { … }

Let's have some fun. I'll leave it up to you to decide whether you should actually use this anywhere... :P

It is possible to (indirectly) declare and initialize as many variables as you want of different types in the for loop initializer without using the dynamic key word. Just use a custom struct for your index variable.

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

Overloaded operators mean you can use "i" like an int everywhere. For a clean syntax, initialize with 0:

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

A few more silly examples:

// 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]);
    }
}

Here are the structs. They do work but are not thoroughly tested so there may be bugs:

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;
    }
}
Related