【问题标题】:Assign value to iteration variable in C#?在C#中为迭代变量赋值?
【发布时间】:2013-03-16 00:07:28
【问题描述】:

我在使用foreach 的C# 中有以下代码。在一个循环中,我正在修改List<T>,在另一个循环中,我正在修改string 数组。

我们不能直接给迭代变量赋值或者null,但是我们可以修改它的属性,修改最终体现在List中。

所以这基本上意味着迭代变量是对列表中元素的引用,那为什么我们不能直接给它赋值呢?

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

【问题讨论】:

  • “不允许”是什么意思?
  • “不允许”表示编译错误。

标签: c# foreach iteration


【解决方案1】:

这里有一个具体的例子,应该清楚。

假设您像这样实现IEnumerable&lt;int&gt;

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,而它与更改被迭代的事物没有任何关系,但这会产生误导 - 这就是编译器不允许它的原因。

【讨论】:

    【解决方案2】:

    它是一个引用类型,当然你可以修改它的属性,如果它们是可写的,这些更改将反映在引用所引用的对象中。

    引用类型的变量根据定义是对对象的引用。但这与对实际存储位置(例如变量或列表条目)的引用不同。

    你可以把它想象成一个Student 变量只包含找到原始对象的地址。通过将列表条目复制到变量中,您只是在复制地址,所以现在您有两个地址,一个在列表中,一个在变量中。通过重新分配变量,您正在向其中写入另一个地址,但这不会影响列表中的原始条目。它也不会覆盖变量之前引用的对象。

    话虽如此,foreach 可能不允许您重新分配迭代变量,因为它可能会导致混淆/错误。它当前的实现方式,你总是知道迭代变量是当前元素。

    【讨论】:

      【解决方案3】:

      这是因为编译器使用Enumerator 实现foreach。枚举器只能在封闭的集合中向前移动,它们不能改变它们迭代的集合。

      【讨论】:

        【解决方案4】:

        foreach 中的迭代变量不是“对列表中元素的引用”——它只是通过GetEnumerator() 获得的迭代器实现中来自.Current {get;} 的值——大多数通常通过IEnumerator[&lt;T&gt;],但并非总是如此 - 实际上对于List&lt;T&gt;,它是List&lt;T&gt;.Enumerator 值。在一般情况下,分配给迭代器变量没有“意义”。考虑:

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

        这将在foreach完全相同工作 - 分配给它意味着什么?

        因此,foreach 不提供分配给迭代器变量的工具。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-12
          • 1970-01-01
          相关资源
          最近更新 更多