Foreach and enumerable

本文关键字:enumerable and Foreach | 更新日期: 2023-09-27 18:27:44

为什么我们可以迭代项目ex

mList.ForEach((item) 
{
    item.xyz ....
}

对于一个简单的数组,我们需要强制foreach循环?

foreach(int i in arr)
    i.xyz

或者使用委托类型?

Action<int> action = new Action<int>(myfunc);
Array.ForEach(intArray, action);

有什么不同?

Foreach and enumerable

第一个语法不正确。应该是这样的:

mList.ForEach(item => 
{
    // item.xyz
});

ForEachList<T>的一种方法,它使您能够为列表中的每个项目调用Action<T>

另一方面,foreach

语句为中的每个元素重复一组嵌入语句实现System.Collections.Enumerable或System.Collections.Generic.IEnumerable接口。

也就是说,ForEach只能在列表上调用,而foreach可以在实现IEnumerable或IEnumerable的任何对象上调用。这就是最大的区别。

关于委托类型,没有任何区别。实际上,lambda表达式item=>{ item.xyz = ...}是委托的简写。

该语言将foreach定义为IEnumerable的操作。因此,实现IEnumerable的所有内容都是可迭代的。但是,当使用ForEach块时,并非所有的IEnumerable都"有意义"。

举个例子:

public static IEnumerable<MyObject> GetObjects()
{
    var i = 0;
    while(i < 30)
        yield return new MyObject { Name = "Object " + i++ };
}

然后你做这样的事情:

var objects = GetObjects();
objects.ForEach(o => o.Name = "Rob");
foreach (var obj in objects)
    Console.WriteLine(obj.Name);

如果编译了,它将打印出Object 0Object 29,而不是Rob 30次。

原因是每次迭代枚举对象时,迭代器都会重置。对于列表上的ForEach来说,这是有意义的,因为枚举对象已经具体化,并且不会在每次迭代时重新创建对象

为了使ForEach在可枚举对象上工作,您还需要具体化集合(例如将其放入列表中),但即使也不总是可能,因为您可以有一个没有定义结束的可枚举对象:

public static IEnumerable<MyObject> GetObjects()
{
    while(true)
        yield return new MyObject { Name = "Object " };
}

Array上有ForEach也是有意义的,但由于我不知道的原因,它被定义为Array.ForEach(arr)而不是arr.ForEach()

这个故事的寓意是,如果你认为你需要一个ForEach块,你可能想首先实现枚举,通常是List<T>或数组(T[])。