可能通过foreach向后迭代?

我知道我可以使用一个for语句并达到相同的效果,但我可以通过在C#中的foreach循环向后循环?

使用列表(直接索引)时,不能像使用for循环一样高效。

编辑:这通常意味着,当你能够使用for循环时,这可能是这个任务的正确方法。 此外,就像foreach被按顺序执行一样,构造本身也是为了表示与元素索引和迭代次序无关的循环而build立的,这在并行编程中是特别重要的。 我认为依靠顺序的迭代不应该使用foreach进行循环。

如果你在.NET 3.5上,你可以这样做:

 IEnumerable<int> enumerableThing = ...; foreach (var x in enumerableThing.Reverse()) 

它不是非常有效率,因为它必须基本上通过统计员把所有东西放在一个堆栈上,然后以相反的顺序popup一切。

如果你有一个直接索引的集合(例如IList),你应该使用for循环。

如果你使用的是.NET 2.0,并且不能使用for循环(也就是说你只需要一个IEnumerable),那么你只需要编写自己的Reverse函数。 这应该工作:

 static IEnumerable<T> Reverse<T>(IEnumerable<T> input) { return new Stack<T>(input); } 

这依赖于一些可能不那么明显的行为。 当你将一个IEnumerable传递给堆栈构造函数时,它将遍历它并将这些项目推送到堆栈上。 当你迭代堆栈时,它会以相反的顺序popup事件。

这和.NET 3.5 Reverse()扩展方法显然会炸毁,如果你喂它一个永远不会停止返回项目的IEnumerable。

正如280Z28所说,对于IList<T>你可以使用索引。 你可以用一个扩展方法隐藏它:

 public static IEnumerable<T> FastReverse<T>(this IList<T> items) { for (int i = items.Count-1; i >= 0; i--) { yield return items[i]; } } 

这将比首先缓冲所有数据的Enumerable.Reverse()快。 (我不相信Reverse会以Count()的方式应用优化Count() 。请注意,这种缓冲意味着数据在第一次迭代时被完全读取,而FastReverse将“看到”对列表所做的任何更改而你迭代。 (如果在迭代之间移除多个项目,它也会中断。)

对于一般序列,没有办法反向迭代 – 序列可能是无限的,例如:

 public static IEnumerable<T> GetStringsOfIncreasingSize() { string ret = ""; while (true) { yield return ret; ret = ret + "x"; } } 

如果你试图迭代它,你会发生什么?

如果你使用一个List <T>,你也可以使用这个代码:

 List<string> list = new List<string>(); list.Add("1"); list.Add("2"); list.Add("3"); list.Reverse(); 

这是一种将自己的列表反向写入的方法。

现在是foreach:

 foreach(string s in list) { Console.WriteLine(s); } 

输出是:

 3 2 1 

在使用'foreach'进行迭代之前,通过'reverse'方法反转列表:

  myList.Reverse(); foreach( List thisList in myList) { Console.WriteLine(thisList); } 

不,ForEach只是迭代通过每个项目的集合和顺序取决于它是否使用IEnumerable或GetEnumerator()。

如果您可以更改实现IEnumerable或IEnumerable 的集合代码 (例如,您自己的IList实现),则可能会发生这种情况。

创build一个Iterator为你做这个工作,例如通过IEnumerable接口实现下面的实现(假设'items'是本示例中的List字段):

 public IEnumerator<TObject> GetEnumerator() { for (var i = items.Count - 1; i >= 0; i--) { yield return items[i]; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 

正因为如此,你的列表将以相反的顺序遍历你的列表。

只是一个提示:你应该清楚地说明你的列表在文档中的这种特殊的行为(甚至更好地select一个自我解释的类名,如堆栈或队列)。

有时你没有索引的豪华,或者你想扭转Linq查询的结果,或者你不想修改源集合,如果其中任何一个是真的,Linq可以帮助你。

使用Linq Select使用匿名types的Linq扩展方法为Linq OrderByDescending提供sorting键;

  public static IEnumerable<T> Invert<T>(this IEnumerable<T> source) { var transform = source.Select( (o, i) => new { Index = i, Object = o }); return transform.OrderByDescending(o => o.Index) .Select(o => o.Object); } 

用法:

  var eable = new[]{ "a", "b", "c" }; foreach(var o in eable.Invert()) { Console.WriteLine(o); } // "c", "b", "a" 

它被命名为“反转”,因为它与“反转”同义,并且可以使用列表反转实现来消除歧义。

因为Int32.MinValue和Int32.MaxValue不在任何types的集合索引的范围内,所以我们可以利用它们来进行sorting过程。 如果元素索引低于给定范围,则将其赋予Int32.MaxValue,以便在使用OrderByDescending时其顺序不会更改,类似地,索引大于给定范围的元素将被赋予Int32.MinValue,以使它们似乎在订购过程结束。 给定范围内的所有元素都被赋予其正常的索引并相应地被反转。

  public static IEnumerable<T> Invert<T>(this IEnumerable<T> source, int index, int count) { var transform = source.Select( (o, i) => new { Index = i < index ? Int32.MaxValue : i >= index + count ? Int32.MinValue : i, Object = o }); return transform.OrderByDescending(o => o.Index) .Select(o => o.Object); } 

用法:

  var eable = new[]{ "a", "b", "c", "d" }; foreach(var o in eable.Invert(1, 2)) { Console.WriteLine(o); } // "a", "c", "b", "d" 

我不确定这些Linq实现的性能命中与使用临时List来包装一个集合进行反转。


在撰写本文的时候,我并没有意识到Linq自己的反向实现,但仍然很有趣。 https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx

我用这个代码工作

  if (element.HasAttributes) { foreach(var attr in element.Attributes().Reverse()) { if (depth > 1) { elements_upper_hierarchy_text = ""; foreach (var ancest in element.Ancestors().Reverse()) { elements_upper_hierarchy_text += ancest.Name + "_"; }// foreach(var ancest in element.Ancestors()) }//if (depth > 1) xml_taglist_report += " " + depth + " " + elements_upper_hierarchy_text+ element.Name + "_" + attr.Name +"(" + attr.Name +")" + " = " + attr.Value + "\r\n"; }// foreach(var attr in element.Attributes().Reverse()) }// if (element.HasAttributes) { 

这工作得很好

 List<string> list = new List<string>(); list.Add("Hello"); list.Add("Who"); list.Add("Are"); list.Add("You"); foreach (String s in list) { Console.WriteLine(list[list.Count - list.IndexOf(s) - 1]); }