在c#中是否有一些我没有遇到过的罕见的语言构造(比如我最近学过的一些,一些在Stack Overflow上)来获得表示foreach循环的当前迭代的值?
例如,我目前根据具体情况做这样的事情:
int i = 0;
foreach (Object o in collection)
{
// ...
i++;
}
在c#中是否有一些我没有遇到过的罕见的语言构造(比如我最近学过的一些,一些在Stack Overflow上)来获得表示foreach循环的当前迭代的值?
例如,我目前根据具体情况做这样的事情:
int i = 0;
foreach (Object o in collection)
{
// ...
i++;
}
当前回答
Ian Mercer在Phil Haack的博客上发表了一个类似的解决方案:
foreach (var item in Model.Select((value, i) => new { i, value }))
{
var value = item.value;
var index = item.i;
}
通过重载LINQ的Select函数,你可以得到item (item.value)和它的索引(item.i):
函数[在Select内部]的第二个参数表示源元素的索引。
新的{i, value}正在创建一个新的匿名对象。
如果你使用c# 7.0或更高版本,可以使用ValueTuple来避免堆分配:
foreach (var item in Model.Select((value, i) => ( value, i )))
{
var value = item.value;
var index = item.i;
}
你也可以删除这个项目。通过使用自动解构:
foreach (var (value, i) in Model.Select((value, i) => ( value, i )))
{
// Access `value` and `i` directly here.
}
其他回答
除非你的集合可以通过某种方法返回对象的索引,否则唯一的方法就是使用像你的例子中那样的计数器。
然而,当使用索引时,唯一合理的答案是使用for循环。其他任何事情都会带来代码的复杂性,更不用说时间和空间的复杂性了。
使用LINQ, c# 7和系统。ValueTuple NuGet包,你可以这样做:
foreach (var (value, index) in collection.Select((v, i)=>(v, i))) {
Console.WriteLine(value + " is at index " + index);
}
您可以使用常规的foreach构造,并能够直接访问值和索引,而不是作为对象的成员,并将这两个字段仅保留在循环的作用域中。基于这些原因,我相信这是最好的解决方案,如果你能够使用c# 7和System.ValueTuple。
我只是遇到了这个问题,但在我的情况下思考这个问题给出了最好的解决方案,与预期的解决方案无关。
It could be quite a common case, basically, I'm reading from one source list and creating objects based on them in a destination list, however, I have to check whether the source items are valid first and want to return the row of any error. At first-glance, I want to get the index into the enumerator of the object at the Current property, however, as I am copying these elements, I implicitly know the current index anyway from the current destination. Obviously it depends on your destination object, but for me it was a List, and most likely it will implement ICollection.
i.e.
var destinationList = new List<someObject>();
foreach (var item in itemList)
{
var stringArray = item.Split(new char[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);
if (stringArray.Length != 2)
{
//use the destinationList Count property to give us the index into the stringArray list
throw new Exception("Item at row " + (destinationList.Count + 1) + " has a problem.");
}
else
{
destinationList.Add(new someObject() { Prop1 = stringArray[0], Prop2 = stringArray[1]});
}
}
我认为,虽然不总是适用,但常常足以值得一提。
不管怎样,关键是有时在你的逻辑中已经有了一个不明显的解决方案……
foreach用于迭代实现IEnumerable的集合。它通过在集合上调用GetEnumerator来实现这一点,该集合将返回一个Enumerator。
这个枚举器有一个方法和一个属性:
MoveNext () 当前的
Current返回Enumerator当前所在的对象,MoveNext将Current更新为下一个对象。
索引的概念与枚举的概念是不同的,不能这样做。
因此,大多数集合都可以使用索引器和for循环构造来遍历。
在这种情况下,与使用局部变量跟踪索引相比,我更喜欢使用for循环。
我不相信有一种方法可以获得foreach循环当前迭代的值。数数自己,似乎是最好的办法。
我能问一下,你为什么想知道?
看起来你最有可能做以下三件事中的一件:
1)从集合中获取对象,但在这种情况下,您已经拥有它。
2)为后期处理计算对象…集合有一个可以使用的Count属性。
3)根据对象在循环中的顺序设置它的属性…尽管您可以在将对象添加到集合时轻松地进行设置。