如何在foreach中引用实际元素

本文关键字:元素 引用 foreach | 更新日期: 2023-09-27 18:04:22

我使用了下面的代码来遍历一个IEnumerable

IEnumerable<Thing> things = ...;
foreach (Thing thing in things)
  thing = method(thing);

编译器不同意,因为我引用了东西,这是迭代变量。当然,我打算影响列表中的底层对象。我怎么做呢?

现在,我使用了一个数值迭代的解决方案,但是有两个问题。首先,我认为这不是一个好的编码。除此之外,它要求我将thingsIEnumerable更改为IList(或者我甚至应该使用List?!),当things变大时,放在我的下背。

//List<Thing> things = ...;
IList<Thing> things = ...;
for (int i = 0; i < things.Count(); i++)
  things[i] = method(things[i]);

如何在foreach中引用实际元素

您可以使用Linq:

投影序列
 var transformedThings = things.Select(t => method(t));

如果要在所有元素上运行该方法,为什么不转换整个集合:

public IEnumerable<Thing> TransformThings(IEnumerable<Thing> input)
{
    foreach (var thing in input)
        yield return method(thing);
}

你可以这样使用:

var transformedThings = TransformThings(things);

这将在您遍历集合时转换每个元素,这意味着您不必将整个集合枚举到内存中。

编辑

更简单:

var transformedThings = things.Select(thing => method(thing));

你不能改变引用时迭代列表中的项目,因为它在枚举器的限制,但你可以改变项目中的对象....

使用强大的linq或只是克隆你的列表,如ToList()或ToArray()。

项目替换可以很容易地完成使用一些集合,例如,数组或List<T>(如您所描述的)通过使用for循环(不是foreach)。

无法用foreach语句替换对象

如果你真的想使用IEnumerable<T>接口,有两个选择:

  1. 变换Thing s序列(参见IEnumerable<T>.Select()方法)。在本例中,Thing 的源序列和源实例没有被修改

    例如:

    var newThings = things.Select(t => new Thing(/* pass different values using original t instance */));
    
  2. 更新每个实例的状态:

    class Thing
    {
        public void UpdateState(/* parameters */)
        {
            // Update field/property values, etc.
        }
    }
    ...        
    foreach (var thing in things)
        thing.UpdateState(/* new values */);
    

如果IEnumerable的长度保持不变,我将使用ToArray()并迭代for循环。

例如:

char[] chars = "somestring".ToArray();
for (int i = 0; i < chars.Length; i++)
{
  chars[i] = SomeMethod();
}

用于修改集合中的内容。

Thing[] things = ...;
for (int i = 0; i < things .Length; i++)
{
  AddOne(ref things[i]);
}
public void AddOne(ref Thing t)
{
  t.Foo += 1;
}