我有一个foreach循环,需要执行一些逻辑时,最后一项是从列表中选择,例如:

 foreach (Item result in Model.Results)
 {
      //if current result is the last item in Model.Results
      //then do something in the code
 }

我可以知道哪个循环是最后没有使用循环和计数器吗?


当前回答

在某些类型上使用Last()将遍历整个集合! 这意味着如果执行foreach并调用Last(),则循环两次!我相信你会尽量避免大量收藏。

那么解决方案是使用while循环:

using var enumerator = collection.GetEnumerator();

var last = !enumerator.MoveNext();
T current;

while (!last)
{
  current = enumerator.Current;        

  //process item

  last = !enumerator.MoveNext();        
  if(last)
  {
    //additional processing for last item
  }
}

因此,除非集合类型为IList<T>,否则Last()函数将遍历所有集合元素。

Test

如果你的集合提供了随机访问(例如实现了IList<T>),你也可以像下面这样检查你的项目。

if(collection is IList<T> list)
  return collection[^1]; //replace with collection.Count -1 in pre-C#8 apps

其他回答

".Last()"对我不起作用,所以我不得不这样做:

Dictionary<string, string> iterativeDictionary = someOtherDictionary;
var index = 0;
iterativeDictionary.ForEach(kvp => 
    index++ == iterativeDictionary.Count ? 
        /*it's the last item */ :
        /*it's not the last item */
);

要对除最后一个元素之外的每个元素做一些额外的事情,可以使用基于函数的方法。

delegate void DInner ();

....
    Dinner inner=delegate 
    { 
        inner=delegate 
        { 
            // do something additional
        } 
    }
    foreach (DataGridViewRow dgr in product_list.Rows)
    {
        inner()
        //do something
    }
}

这种方法有明显的缺点:对于更复杂的情况,代码更不清晰。调用委托可能不是很有效。排除故障可能不太容易。好的一面——编码很有趣!

话虽如此,如果你知道你的集合的计数不是特别慢,我建议在一些不重要的情况下使用plain for循环。

如何将foreach转换为对最后一个元素做出反应:

List<int> myList = new List<int>() {1, 2, 3, 4, 5};
Console.WriteLine("foreach version");
{
    foreach (var current in myList)
    {
        Console.WriteLine(current);
    }
}
Console.WriteLine("equivalent that reacts to last element");
{
    var enumerator = myList.GetEnumerator();
    if (enumerator.MoveNext() == true) // Corner case: empty list.
    {
        while (true)
        {
            int current = enumerator.Current;

            // Handle current element here.
            Console.WriteLine(current);

            bool ifLastElement = (enumerator.MoveNext() == false);
            if (ifLastElement)
            {
                // Cleanup after last element
                Console.WriteLine("[last element]");
                break;
            }
        }
    }
    enumerator.Dispose();
}

你可以只使用一个for循环,不需要在for体中添加额外的if:

for (int i = 0; i < Model.Results.Count - 1; i++) {
    var item = Model.Results[i];
}

for条件中的-1负责跳过最后一项。

还有更简单的方法吗?

Item last = null;
foreach (Item result in Model.Results)
{
    // do something with each item

    last = result;
}

//Here Item 'last' contains the last object that came in the last of foreach loop.
DoSomethingOnLastElement(last);