-1

Environment: C#, VS2012, SharePoint 2010

I'm using a console application to interface with a SharePoint site and I'm trying to do a simple string comparison against a collection of alert titles... but when debugging I am getting an "out of range" exception sometimes on a specific string. Here's the code snippet:

// This is pointing to a txt file with two lines in it, "folder1" and "folder3"
string[] aTitleList = System.IO.File.ReadAllLines(@"c:\path\to\specific\file.txt");
// Now we iterate through all the alerts to compare titles against those two lines
for (int i = oAlertCollection.Count - 1; i > -1; i--)
{
    System.Guid guid = oAlertCollection[i].ID;
    foreach (string sTitle in aTitleList)
    {
        if (oAlertCollection[i].Title.Contains(sTitle))
        {
            // At this point it throws the exception on the sTitle string
            // But ONLY on "folder3" and ONLY about half of the time
            // If I change it to something other than "folder3" it works 100%
        }
    }
}

Does that seem bizarre to anyone else? I have tons of other methods in this application that do similar comparisons and have no problems, even when using the "folder3" string, it's only when I use this specific array that I run into trouble.

Edit 1 - In-depth explanation of loop: The loop in this case is deleting the items that match the given strings. The way the loop is set up, it starts with the last item and iterates until it reaches 0 (this is because SharePoint automatically shifts the ID of each item in a collection down to replace the one that was deleted so there are no gaps, this is also where it gets the Count method, looking at the highest numbered ID in the collection). To clarify: The Count method returns the total number of alerts, but the actual alert IDs start at 0, so the for loop adjusts the count before using i to index them. If the Count method returns 0 elements, the for loop sets that to -1 and does not fire.

Edit 2 - Test results: I have been battery testing the app and while I still cannot find a consistency between when it works/bombs while using 2 items in the array, I discovered something that may shed some light on the cause. If I increase the array to 3 items, it will fail consistently. The problem comes when the first or second string comparison is true and the item is deleted, because the foreach loop does not exit at that point, it continues to test the remaining strings against the now non-existent alert, which throws the exception. When this happens with only two items in the array, testing the second item after the first one triggered the delete does not always throw an exception. Half of the time it "tests" the deleted alert as if it were still there and continues with the main loop.

For reference, this is the explanation of how SPAlertCollection works. Could it perhaps be holding the alert in memory briefly even after it's deleted? That's the only way I could see it NOT throwing an exception every time it tests the deleted alert.

Final Edit: The questions is answered well enough, the struck-through section is still unanswered but ultimately not relevant to the situation.

thanby
  • 323
  • 1
  • 6
  • 22
  • 2
    How does oAlertCollection get its count? Can oAlertCollection.Count be 0? – Tim Mar 04 '13 at 22:27
  • Think about what the values of `i` are when `oAlertCollection` is empty. (Just use LINQ and `foreach (var alert : oAlertCollection.Reverse())`. Also, I'd drop the Hungarian, it's beyond pointless for local variables.) – millimoose Mar 04 '13 at 22:27
  • Yeah, that's pretty bizarre. Are you able to catch the exception and see if `i` is in the range `0..oAlertCollection.Count-1`? Are you by chance deleting things from the `oAlertcollection`? – Jim Mischel Mar 04 '13 at 22:29
  • If my guess above is wrong, you still need to do more diagnosis. "Only when it feels like it" isn't much to go on. You haven't told us what the values of `i` and `oAlertCollection` are at the point where the error occurs, or even which line it happens on. – millimoose Mar 04 '13 at 22:31
  • Btw, linq would be much more readable: `foreach(var alert in oAlertCollection.Where(a => aTitleList.Contains(a.Title))){//...}` – Tim Schmelter Mar 04 '13 at 22:33
  • @TimSchmelter @millimoose Hungarian? Also, I will look into diagnosing it with LINQ, but for reference it is bombing on the `if` statement, at which point it is testing multiple strings against the alert title. See my second edit for the full explanation. – thanby Mar 05 '13 at 19:58

1 Answers1

2

As pointed out by Jim Mischel the following can only happen if you happen to delete elements from oAlertCollection in your loop


I'm going out on a limb and assume your oAlertCollection can sometimes hold 0 elements, which is why your code crashes on this line

if (oAlertCollection[i].Title.Contains(sTitle))

You'd then be trying to access position -1 in the array which throws an outofrange exception

You could avoid this by checking for oAlertCollection.Count's value before looping like this

if(oAlertCollection.Count() > 0)
{
    //for loop
}

This way if it actually holds 0 elements you avoid the error because it will not enter the loop

Tim
  • 41,901
  • 18
  • 127
  • 145
  • 1
    This can only happen if he's removing items from `oAlertCollection` somewhere in the loop. I suspect that's the cause. – Jim Mischel Mar 04 '13 at 22:38
  • Thanks for the suggestion, I'll give it a shot just in case. However, when the exception is thrown, `i` always contains a positive value. – thanby Mar 05 '13 at 13:40
  • 1
    Then maybe `i` contains a value higher than `oAlertCollection.Count - 1`, that would also throw an exception – Tim Mar 05 '13 at 14:10
  • I just went through and checked every scenario for it, the problem does have to do with `i` being higher than `Count - 1` but there's a twist... too much to explain in a comment so I'll edit it into the question. – thanby Mar 05 '13 at 19:17