在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++;
}
当前回答
我只是遇到了这个问题,但在我的情况下思考这个问题给出了最好的解决方案,与预期的解决方案无关。
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]});
}
}
我认为,虽然不总是适用,但常常足以值得一提。
不管怎样,关键是有时在你的逻辑中已经有了一个不明显的解决方案……
其他回答
我只是遇到了这个问题,但在我的情况下思考这个问题给出了最好的解决方案,与预期的解决方案无关。
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]});
}
}
我认为,虽然不总是适用,但常常足以值得一提。
不管怎样,关键是有时在你的逻辑中已经有了一个不明显的解决方案……
这是我刚想到的解决这个问题的办法
原始代码:
int index=0;
foreach (var item in enumerable)
{
blah(item, index); // some code that depends on the index
index++;
}
更新代码
enumerable.ForEach((item, index) => blah(item, index));
扩展方法:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T, int> action)
{
var unit = new Unit(); // unit is a new type from the reactive framework (http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx) to represent a void, since in C# you can't return a void
enumerable.Select((item, i) =>
{
action(item, i);
return unit;
}).ToList();
return pSource;
}
我不同意在大多数情况下使用for循环是更好的选择的说法。
Foreach是一个有用的构造,在所有情况下都不能被for循环所取代。
例如,如果您有一个DataReader,并使用foreach循环遍历所有记录,它会自动调用Dispose方法并关闭阅读器(然后自动关闭连接)。因此,这是更安全的,因为它可以防止连接泄漏,即使您忘记关闭读取器。
(当然,总是关闭读取器是很好的做法,但如果你不这样做,编译器就不会捕捉到它——你不能保证你已经关闭了所有的读取器,但你可以通过养成使用foreach的习惯,使它更有可能不会泄漏连接。)
对于Dispose方法的隐式调用,可能还有其他有用的例子。
只需添加自己的索引。保持简单。
int i = -1;
foreach (var item in Collection)
{
++i;
item.index = i;
}
最后,c# 7有一个不错的语法,用于在foreach循环(即元组)中获取索引:
foreach (var (item, index) in collection.WithIndex())
{
Debug.WriteLine($"{index}: {item}");
}
需要一个小扩展方法:
using System.Collections.Generic;
public static class EnumExtension {
public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> self)
=> self.Select((item, index) => (item, index));
}