在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++;
}
当前回答
我在LINQPad中构建了这个:
var listOfNames = new List<string>(){"John","Steve","Anna","Chris"};
var listCount = listOfNames.Count;
var NamesWithCommas = string.Empty;
foreach (var element in listOfNames)
{
NamesWithCommas += element;
if(listOfNames.IndexOf(element) != listCount -1)
{
NamesWithCommas += ", ";
}
}
NamesWithCommas.Dump(); //LINQPad method to write to console.
你也可以使用string.join:
var joinResult = string.Join(",", listOfNames);
其他回答
我不同意在大多数情况下使用for循环是更好的选择的说法。
Foreach是一个有用的构造,在所有情况下都不能被for循环所取代。
例如,如果您有一个DataReader,并使用foreach循环遍历所有记录,它会自动调用Dispose方法并关闭阅读器(然后自动关闭连接)。因此,这是更安全的,因为它可以防止连接泄漏,即使您忘记关闭读取器。
(当然,总是关闭读取器是很好的做法,但如果你不这样做,编译器就不会捕捉到它——你不能保证你已经关闭了所有的读取器,但你可以通过养成使用foreach的习惯,使它更有可能不会泄漏连接。)
对于Dispose方法的隐式调用,可能还有其他有用的例子。
出于兴趣,Phil Haack刚刚在Razor Templated Delegate的上下文中写了一个例子(http://haacked.com/archive/2011/04/14/a-better-razor-foreach-loop.aspx)。
实际上,他编写了一个扩展方法,将迭代包装在一个“IteratedItem”类中(见下文),允许在迭代期间访问索引和元素。
public class IndexedItem<TModel> {
public IndexedItem(int index, TModel item) {
Index = index;
Item = item;
}
public int Index { get; private set; }
public TModel Item { get; private set; }
}
然而,如果你在非razor环境中做一个单独的操作(例如,一个可以作为lambda提供的操作),这在非razor环境中不会是for/foreach语法的可靠替代。
foreach用于迭代实现IEnumerable的集合。它通过在集合上调用GetEnumerator来实现这一点,该集合将返回一个Enumerator。
这个枚举器有一个方法和一个属性:
MoveNext () 当前的
Current返回Enumerator当前所在的对象,MoveNext将Current更新为下一个对象。
索引的概念与枚举的概念是不同的,不能这样做。
因此,大多数集合都可以使用索引器和for循环构造来遍历。
在这种情况下,与使用局部变量跟踪索引相比,我更喜欢使用for循环。
我在LINQPad中构建了这个:
var listOfNames = new List<string>(){"John","Steve","Anna","Chris"};
var listCount = listOfNames.Count;
var NamesWithCommas = string.Empty;
foreach (var element in listOfNames)
{
NamesWithCommas += element;
if(listOfNames.IndexOf(element) != listCount -1)
{
NamesWithCommas += ", ";
}
}
NamesWithCommas.Dump(); //LINQPad method to write to console.
你也可以使用string.join:
var joinResult = string.Join(",", listOfNames);
c# 7最终为我们提供了一种优雅的方式:
static class Extensions
{
public static IEnumerable<(int, T)> Enumerate<T>(
this IEnumerable<T> input,
int start = 0
)
{
int i = start;
foreach (var t in input)
{
yield return (i++, t);
}
}
}
class Program
{
static void Main(string[] args)
{
var s = new string[]
{
"Alpha",
"Bravo",
"Charlie",
"Delta"
};
foreach (var (i, t) in s.Enumerate())
{
Console.WriteLine($"{i}: {t}");
}
}
}