在通用列表中,List.Last() 即使在检查 Count 之后也会抛出 System.IndexOutOfRangeException

In generic list, List.Last() throws System.IndexOutOfRangeException even after check of Count

我的 WCF 服务中有以下代码,它抛出 System.IndexOutOfRangeException

Dictionary<string, List<ChunkData>> chunkDataTable = cacheManager[cacheKey] as Dictionary<string, List<ChunkData>>;
  if (!chunkDataTable.Keys.Contains(ticker))
  {
      chunkDataTable.Add(ticker, new List<ChunkData>());
  }
  List<ChunkData> listOfChunks = new List<ChunkData>();
  ChunkData lastIncompeleteChunk = null;
  if (chunkDataTable[ticker].Count > 0)
  {
      Logger.Write("Log one");  //I see this logs
  if (reqEndDate <= chunkDataTable[ticker].Last().EndDate)
  {
      //meaning we can directly take last chunk (which can be incompelete too) directly as we dont need to add further data into for now
      listOfChunks = chunkDataTable[ticker].Where
          (chunk =>
            ((chunk.StartDate >= reqStartDate && chunk.EndDate <= reqEndDate) ||      //whole chunks: which lies in between of requested start and end date
            (chunk.StartDate <= reqStartDate && reqStartDate <= chunk.EndDate) ||     //Left Most Chunk: if req start date lies within some chunk (between start and end date of chunk)
            (chunk.StartDate <= reqEndDate && reqEndDate <= chunk.EndDate)            //Right Most Chunk: if req end date lies within some chunk (between start and end date of chunk)
            )).OrderBy(x => x.EndDate).ToList();
  }
  else
  {
      listOfChunks = chunkDataTable[ticker].Where
        (chunk => !chunk.IsIncomplete &&
            ((chunk.StartDate >= reqStartDate && chunk.EndDate <= reqEndDate) ||      //whole chunks: which lies in between of requested start and end date
            (chunk.StartDate <= reqStartDate && reqStartDate <= chunk.EndDate) ||     //Left Most Chunk: if req start date lies within some chunk (between start and end date of chunk)
            (chunk.StartDate <= reqEndDate && reqEndDate <= chunk.EndDate)            //Right Most Chunk: if req end date lies within some chunk (between start and end date of chunk)
            )).OrderBy(x => x.EndDate).ToList();
      if (chunkDataTable[ticker].Last().IsIncomplete)
          lastIncompeleteChunk = chunkDataTable[ticker].Last();
  }

  if (listOfChunks != null)
      Logger.Write("Line two"); //I don't see this log

}

此处 reqEndDatereqStartDate 来自客户端计算机,根据日志,它们是正确的。 cacheManager 是 Microsoft 企业库的缓存管理器

完整堆栈跟踪:

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at System.Linq.Enumerable.Last[TSource](IEnumerable`1 source)

我想知道,这种异常可能在什么时候发生

堆栈跟踪表明这是一个威胁问题。 Last() 是这样实现的:

IList<TSource> sourceList = source as IList<TSource>;
if (sourceList != null)
{
    int count = sourceList.Count;
    if (count > 0)
      return sourceList[count - 1];
}

因此,如果 IEnumerable 您传递了 implements IList (就像您的情况一样),它将首先将总长度保存在一个变量中,然后访问最后一个元素。如果 source 中的元素数量在 sourceList.CountsourceList[count - 1] 语句之间发生更改,则可以抛出堆栈跟踪异常的唯一方法,这只能由另一个线程完成。

如果您正在使用共享缓存 - 可以由另一个 WCF 线程进行更改。因此,要修复 - 在处理共享缓存中的项目时实施正确的同步。