3

私はC#で次のコードを利用していforeachます。あるループでは、を変更しList<T>、別のループではstring配列を変更しています。

反復変数に値またはnullを直接割り当てることはできませんが、そのプロパティを変更することはでき、変更はListfinallyに反映されます。

つまり、これは基本的に、反復変数がリスト内の要素への参照であることを意味します。それでは、なぜ直接値を割り当てることができないのでしょうか。

class Program
{
    public static void Main(string[] args)
    {
        List<Student> lstStudents = Student.GetStudents();

        foreach (Student st in lstStudents)
        {
            // st is modified and the modification shows in the lstStudents
            st.RollNo = st.RollNo + 1;

            // not allowed
            st = null;
        }

        string[] names = new string[] { "me", "you", "us" };

        foreach (string str in names)
        {
            // modifying str is not allowed
            str = str + "abc";
        }
    }
}

学生クラス:

class Student
{
    public int RollNo { get; set; }
    public string Name { get; set; }

    public static List<Student> GetStudents()
    {
        List<Student> lstStudents = new List<Student>();

        lstStudents.Add(new Student() { RollNo = 1, Name = "Me" });
        lstStudents.Add(new Student() { RollNo = 2, Name = "You" });
        lstStudents.Add(new Student() { RollNo = 3, Name = "Us" });

        return lstStudents;
    }
}
4

4 に答える 4

9

aの反復変数は、「リスト内の要素への参照」でforeachはありません.Current {get;}。これは、を介して取得されたイテレータ実装の値にすぎません。GetEnumerator()最も一般的には、を介して取得されますIEnumerator[<T>]が、常にではありません。実際、aList<T>List<T>.Enumerator値です。一般的な場合、イテレータ変数に割り当てる「意味」はありません。検討:

IEnumerable<int> RandomSequence(int count) {
    var rand = new Random();
    while(count-->0) yield return rand.Next();
}

これは-から同じforeachように機能します-それに割り当てるとはどういう意味ですか?

したがって、foreachイテレータ変数に割り当てる機能はありません。

于 2013-03-26T09:03:32.543 に答える
2

これは、コンパイラが。を使用して実装foreachするためEnumeratorです。列挙子は、閉じたコレクション内でのみ前方移動でき、反復するコレクションを変更することはできません。

于 2013-03-26T09:04:26.697 に答える
1

これは参照型です。もちろん、書き込み可能であればそのプロパティを変更でき、それらの変更は参照が参照するオブジェクトに反映されます。

参照型の変数は、定義上、オブジェクトへの参照です。ただし、これは実際の保存場所(変数やリストエントリなど)への参照とは異なります。

Student変数に元のオブジェクトを見つけるアドレスだけが含まれているように想像できます。リストエントリを変数にコピーすることで、アドレスをコピーするだけなので、リストに1つ、変数に1つ、合計2つのアドレスが作成されます。変数を再割り当てすることにより、別のアドレスをその変数に書き込んでいますが、それはリストの元のエントリには影響しません。また、変数が以前に参照したオブジェクトを上書きしません。

そうは言っても、foreach混乱やバグにつながる可能性があるため、おそらく反復変数を再割り当てすることはできません。現在の実装方法では、反復変数が現在の要素であることを常に知っています。

于 2013-03-26T09:04:09.073 に答える
1

これは、それを明確にする必要がある具体的な例です。

IEnumerable<int>次のように実装するとします。

public static IEnumerable<int> OneToTen()
{
    for (int i = 1; i <= 10; ++i)
    {
        yield return i;
    }
}

それを考えると、次のループで割り当てることができるとしたらどういう意味nですか?

foreach (var n in OneToTen())
{
    n = 1; // Change original "collection"? There isn't one!
}

コンパイラーは、繰り返されるものを変更することとは何の関係もなく、変更を許可することができますが、誤解を招く可能性があります。そのため、コンパイラーはそれを許可しません。n

于 2013-03-26T09:21:37.233 に答える