C#for
ループで異なる型の複数の変数を初期化するにはどうすればよいですか(可能な場合)。例:
for (MyClass i = 0, int j = 1; j<3; j++,i++)
できません。ループの前に宣言の1つを置きます。
MyClass i = 0;
for (int j = 1; j < 3; j++, i++)
または対称性のために、両方とも:
MyClass i = 0;
int j = 1;
for (; j < 3; j++, i++)
変数の1つが他の変数よりもプライマリである可能性もあります。その場合、一方をループ変数にし、次のようにもう一方を別々に処理する方が適切かもしれません。
MyClass i = 0;
for (int j = 0; j < 3; j++)
{
...
i++;
}
i
とj
が同じタイプの場合、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++, 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;
}
すてきな一日を!
はい、できます。 forステートメント内で異なるタイプの変数を初期化できますが、forステートメント内でdeclare異なるタイプの変数を初期化することはできません。 forステートメント内の異なる型の変数を初期化するには、must forループの前にすべての型を宣言します。例えば:
int xx;
string yy;
for(xx=0, yy=""; xx<10; xx++)
{
....
}
[編集]完全性のために情報を追加します。これは、OPが要求したものを超えていますが、他の人にとっては役立つかもしれません。 forループで同じ型の変数を初期化するのは簡単で、初期化をカンマで区切るだけです。 3番目のセクションで複数の変数を変更することもできます。 2番目の比較セクションに複数のコンマ区切りセクションを含めることはできませんが、&& ||を使用できます。そして!複数の変数に基づいて複雑なブールセクションを作成します。
for(int i=0, j=0, k=99; i<10 && k<200; i++, j++, k += 2)
ただし、何が起こっているのかを理解するのが難しいほど複雑なforステートメントを作成することはお勧めできません。
有害ですか?
はい、とてもそうです。言語パーサーにはtwo重要な義務があります。 1つは、誰もがよく知っている仕事で、テキストを実行可能プログラムに変換します。ただし、veryも重要です-無効プログラムを検出し、プログラマーに意味のある診断を生成して修正できることです彼のコード。
非常に基本的なレベルでは、言語パーサーは宣言、文を区別しますおよびexpressions。中括弧言語はその区別を曖昧にします。セミコロンを後に置くだけで、式をステートメントに変えることができます。また、ステートメント内で宣言を受け入れる場合もありますが、for(;;)ステートメントは良い例です。最も明白なのは、この構文はCまたはC++言語で完全に受け入れられることです。
int x = 42;
x;
それは正確に良いことではありません、それはナンセンスコードです。 C#言語はその水準を引き上げましたが、それを拒否します。だがしかし:
int x = 42;
x++;
これを受け入れるために言語パーサーに追加された特別なルール。
中括弧言語が受け入れないものは、宣言を式に変えることです。その方法は狂気にあり、ドラゴンはマップの終わりにあり、船はエッジから落ちて、報告すべき良いメッセージはありません。コンマ演算子では、左側のオペランドと右側のオペランドが式である必要があります。宣言は表現ではなく、物語の終わりです。
通常、ループの前に宣言を置き、追加の中括弧を使用して宣言の範囲を制限します。
{ //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 ) )
{
//...
}
}
C#7では、タプルを使用します。
for (var foo = (i:new MyClass(0), j:1); foo.j < 3; foo.i++, foo.j++)) { … }
for (initializer; condition; iterator)
{
//body
}
の 初期化子 セクションは初期条件を設定します。このセクションのステートメントは、ループに入る前に1回だけ実行されます。セクションには、次の2つのオプションのいずれかのみを含めることができます。
1)ローカルループ変数の宣言と初期化。変数はループに対してローカルであり、ループ外からはアクセスできません。
2)コンマで区切られた、次のリストのゼロ以上のステートメント式:
割り当てステートメント。
メソッドの呼び出し。
++ iやi ++などの前置または後置インクリメント式。
--iやi--などの前置または後置デクリメント式。
Newを使用したオブジェクトの作成。
式を待つ;
私たちが知っているように、コンパイラは私たちが期待する方法を受け入れるように設計されていません。したがって、上記はルールを記述する前に従わなければならないルールです 初期化セクション forループ内。
ループ構造に複数の変数を定義することはできません。以下のコードを試してください:
オプション1:ループの前に宣言され、反復ごとにループで手動で増分される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:両方の変数はループ構造の前に設定され、両方の変数はループ内で増分され、ループは条件をチェックするだけになります。この時点で、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++
}
楽しもう。実際にこれをどこでも使用すべきかどうかはあなた次第です...:P
ダイナミックキーWordを使用せずに、forループ初期化子で(間接的に)さまざまな型の変数を必要な数だけ宣言および初期化できます。インデックス変数にカスタム構造体を使用するだけです。
for(var i = new I1<MyClass>(0, 1); i < 3; i++, i.a++) {
MyClass myClass = i.a;
}
オーバーロードされた演算子は、どこでもintのように「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;
}
}
これは特に私の専門知識ではありませんが、このトピックに関するブレーンストーミングです。
プログラム言語理論では、言語の構文はあいまいさなしに定義する必要があります。これらのトピックを研究してから数年が経ちましたので、私はそれについて非常に詳細に話をすることはできません。ただし、 Backus-Naur Form を確認することはできます。これは、言語の「文法」を記述するための表記法です。そして、それは私が精通している唯一のものです。
そのため、この説明はコードの解析中に使用されます。また、パーサーは、コードのすべての部分を文法の「ルール」に関連付けることができる必要があります。 C#Grammar 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ループでのみ使用されることに注意してください。また、ステートメント式のコンマ区切りリストです。
ここではいくつかの中間ステップを残しますが、文法に従って、アイデアに慣れてください。
ここ は、非常に単純な文法でも複雑なことがどのように得られるかを示すスライドの優れた基本セットです。
(2)1で観察したのは、forループのforイニシャライザー部分に置くことができるものです。そして、あなたの提案がうまくいかない理由を知っています。バウンティハンターになるために、この設計選択の理由を分析しましょう。
まず、これは設計上の選択です。それを可能にする言語を設計または見つけることができます。文法を変更することで可能になるはずですが、構文上の変更が必要になる場合があります。その理由は次のとおりです。
複数の宣言ステートメントを配置する場合、declaration-listのようなものが必要になる場合があります。そして、セパレーターに使用するものは、おそらく使用したくないでしょう。セミコロンはforループの部分を分離するために使用されるためです。したがって、いつでもカンマを使用できますが、コンマを使用する場合、宣言リスト規則はforループでのみ使用できます。コード全体にコンマ区切りの宣言があると混乱するためです。
第二に、それは何が悪いのですか?あなたが私に尋ねた場合、私も何も間違って表示されません。彼らが言語を設計していれば、それはうまくいくはずだった。 (今作成したスケッチが100%正しいと言っているのではなく、ブレインストーミングセッションの開始点としてのみ使用できます。)
それでは、なぜ彼らはそうしなかったのですか?それを避けるために彼らを押したのは何ですか?
これらすべておよび他の多くの考慮事項の後、
...そしてこれらのような非常に多くの質問は、慎重に考えなければなりません。そして、それらの質問とその分析を見ると、コンパイラー設計者の設計選択が最も受け入れられるアプローチだったと思います。
代替インデクサーをインバンドで初期化しない理由はほとんどありません。これにより、環境がゴミの多い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
}
Forループ内で複数の型を定義できるとは思わない。のみ(int i = 0、j = 3; j <7; j ++、i ++)