在foreach循环中改变对象的值?

35

我在一个地方使用字符串列表,在这种情况下,我能够像下面的代码一样改变字符串的值:

foreach(string item in itemlist.ToList())
{
    item = someValue; //I am able to do this 
}

但对于类的对象,我无法更改对象的成员值。代码如下:

public class StudentDTO
{
    string name;
    int rollNo;
}

studentDTOList=GetDataFromDatabase();

foreach(StudentDTO student in studentDTOList.ToList())
{
      student = ChangeName(student); //Not working 
}

private StudentDTO ChangeName(StudentDTO studentDTO)
{
     studentDTO.name = SomeName;
     return studentDTO;
}

错误是:无法分配,因为它是迭代变量


19
不,你确实不能在第一个片段中编写这个代码。迭代变量是只读的。 - Jon Skeet
我能够做到这一点是因为使用了.ToList()方法,它会复制列表并遍历该副本,因此它可以正常工作。 - user2553512
3
不,你不能这样做。试试看吧,代码将无法编译。如果你真的相信它能编译通过,请提供一个简短但完整的程序来证明它——你会发现它会失败。 - Jon Skeet
1
你可以在循环中修改 ToList() 克隆的 list,然后在循环结束后将 list 赋值为新的 ToList() 修改后的产品。 - Mr Heelis
1
只是一个小提示,超过2个字母的缩写应该使用PascalCase。例如,你的类应该被称为StudentDto。 - David Klempfner
3个回答

39

你不能改变 foreach 循环的迭代变量,但是你可以改变迭代变量的成员。因此,请将 ChangeName 方法更改为

private void ChangeName(StudentDTO studentDTO)
{
    studentDTO.name = SomeName;
}
注意,studentDTO是一个引用类型。因此,没有必要返回更改后的学生。ChangeName方法得到的不是学生的副本,而是对唯一学生对象的引用。迭代变量和studentDTOList都引用同一个学生对象,方法的studentDTO参数也是如此。 并将循环修改为:
foreach(StudentDTO student in studentDTOList)
{
    ChangeName(student);
}

然而,像 ChangeName 这样的方法是不寻常的。正确的做法是将字段封装在属性中。

private string name;
public string Name
{
    get { return name; }
    set { name = value; }
}

然后您可以更改循环为

foreach(StudentDTO student in studentDTOList)
{
    student.Name = SomeName;
}

编辑

根据您的评论,您需要更改很多字段。在这种情况下,可以有一个名为UpdateStudent的方法来执行所有更改操作;但是我仍然建议保留属性。

如果属性除了传递值之外没有其他逻辑,您可以使用方便的自动实现属性来替换它们。

public string Name { get; set; }
在这种情况下,你需要删除 name 字段。

2
所以我不需要从函数中返回任何东西,因为它已经获取了引用类型的参数。 - user2553512
1
是的。即使您返回了学生,也可以安全地忽略返回值并不将其分配给迭代变量。返回学生允许您链接方法调用:student.UpdateValues().StoreChanges().PrintReport(); - Olivier Jacot-Descombes

21

实际上您并没有改变所引用的对象,因此您可以直接使用:

foreach (StudentDTO student in studentDTOList)
{
    student.name = SomeName;
}

或者仍然调用一个方法:

foreach (StudentDTO student in studentDTOList)
{
    ChangeStudent(student);
}
在这两种情况下,代码都不会改变迭代变量(student)的值,因此没有问题。
但是你原来的例子无论如何都无法编译-由foreach循环引入的迭代变量是只读的。

实际上,我正在提供一个代码示例。我的原始代码正在从该变量更改许多值,但是使用普通的foreach()无法正常工作,它会显示错误。 - user2553512
2
@user2553512:“它显示错误”绝不是足够的信息……而且在对象内部更改大量数据是可以的,只是不能将新值分配给迭代变量本身。因此,您可以调用ChangeStudent(student)来更改数据-您只是不能执行student = ChangeStudent(student) - Jon Skeet
1
@DnshPly9:主要是因为它几乎永远不会做你想要的事情。例如,它不会改变你正在迭代的东西... - Jon Skeet
那我应该怎么做呢? - user2553512
1
@user2553512:我在答案中一开始就已经给你展示了。 - Jon Skeet
显示剩余5条评论

0

我使用了For循环而不是Foreach,这样我也可以得到需要更改的索引,然后我调用一个函数,在其中传递要更改的数据以及要更改的索引:

  for(int i = 0; i< myList.Count; i++)
  {
    if(mylist[i] == otherData)
    {
      //call the function
      ChangeData(otherData, i);
    }
  }
  
  
  
  
  
  public void ChangeData(DataType DataToChangeInto, int i)
  {
    mylist[i] = DataToChangeInto;
  }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接