Linq.Enumerable中的索引超出界限

时间:2014-12-03 17:05:44

标签: c# linq

我在我正在处理的服务中间歇性地收到此错误

  

消息:System.IndexOutOfRangeException:索引超出了数组的范围。   在System.Collections.Generic.List 1.Enumerator.MoveNext() at System.Linq.Enumerable.<ExceptIterator>d__99 1.MoveNext()   在System.Linq.Enumerable.ElementAtOrDefault [TSource](IEnumerable`1 source,Int32 index)

代码如下所示:

List<ApplicationNames> originalApplicationNames = new List<ApplicationNames>(copyOfCachedVersions.Keys.ToList());
var exceptNames = applicationNames.Except( originalApplicationNames );
if (exceptNames != null && exceptNames.ElementAtOrDefault(0) != default(ApplicationNames))

基本上,if语句应该检查exceptNames是否有任何元素。我已经尝试过使用exceptNames.Count()&gt; 0和exceptNames.Any(),我得到相同的错误消息。我也试过了

var exceptNames = applicationNames.Except( originalApplicationNames ).ToList(); 

结果相同

我真的陷入了这一点,所以任何帮助都会非常感激!

1 个答案:

答案 0 :(得分:4)

  

applicationNames是一个静态对象,因此多个线程可以同时访问它。但是,存在锁定以防止它们同时修改它

当可以同时修改和读取集合时,仅防止并发修改是不够的。您需要防止与修改同时发生的读取,否则您会看到随机异常。

您可以通过复制applicationNames

来解决此问题
private static IList<ApplicationNames> ApplicationNamesSync {
    get {
        // Use the same synchronization that prevents concurrent modifications
        lock (appNamesLock) {
            return applicationNames.ToList(); // Make a copy
        }
    }
}

现在您的代码将起作用:

List<ApplicationNames> originalApplicationNames = new List<ApplicationNames>(copyOfCachedVersions.Keys.ToList());
var exceptNames = ApplicationNamesSync.Except( originalApplicationNames );
if (exceptNames != null && exceptNames.ElementAtOrDefault(0) != default(ApplicationNames)) {
    ...
}