Darendal
Darendal

Reputation: 863

Index Out of Bounds in Linq.Enumerable

I've been getting this error intermittently in a service I'm working on

Message: System.IndexOutOfRangeException: Index was outside the bounds of the array. at System.Collections.Generic.List1.Enumerator.MoveNext() at System.Linq.Enumerable.<ExceptIterator>d__991.MoveNext() at System.Linq.Enumerable.ElementAtOrDefault[TSource](IEnumerable`1 source, Int32 index)

The code looks like this:

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

Basically, the if statement is supposed to check if exceptNames has any elements. I've already tried using exceptNames.Count() > 0 and exceptNames.Any(), and I get the same error message. I've also tried

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

With the same results

I'm really stuck at this point, so any help would be greatly appreciated!

Upvotes: 2

Views: 3798

Answers (1)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

applicationNames is a static object, so several threads would have access to it simultaneously. However, there is locking in place to prevent them from modifying it concurrently

When a collection can be modified and read at the same time, it is not enough to prevent concurrent modification. You need to prevent reads that happen concurrently with modification, otherwise you would see random exceptions.

You can work around this by making a copy of applicationNames:

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

Now your code will work:

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

Upvotes: 5

Related Questions