views:

415

answers:

6

Under what situations would this code error out with System.StackOverflowException?

Accounts.Sort((x, y) => string.Compare(x.AccountId, y.AccountId));

Update:
the property is written as:

    public string AccountId
    {
        get { return _accountId; }
        set { _accountId = value; }
    }

Nothing special going on at all. Sort is not overridden either.

+4  A: 

Here's an off-the-wall idea:

Is Accounts declared as List<Account>?

I'm wondering if Accounts is a property declared as something other than List<Account> -- for instance, as IList<Account> -- and you have a static helper class somewhere with a Sort extension method that isn't implemented properly. This could attempt to leverage the List<T>.Sort method when the parameter passed in is a List<T>, but do so without performing the necessary cast to List<T>, resulting in a guaranteed StackOverflowException.

What I mean is this. Suppose Account is a property of some class that looks something like this:

public class AccountManager
{
    public IList<Account> Accounts { get; private set; }

    public AccountManager()
    {
        // here in the constructor, Accounts is SET to a List<Account>;
        // however, code that interacts with the Accounts property will
        // only know that it's interacting with something that implements
        // IList<Account>
        Accounts = new List<Account>();
    }
}

And then suppose elsewhere you have this static class with a Sort extension method:

public static class ListHelper
{
    public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
    {
        // programmer tries to use the built-in sort, if possible
        if (list is List<T>)
        {
            // only problem is, list is here still typed as IList<T>,
            // so this line will result in infinite recursion
            list.Sort(comparison);

            // the CORRECT way to have done this would've been:
            // ((List<T>)list).Sort(comparison);

            return;
        }
        else
        {
            list.CustomSort(comparison);
            return;
        }
    }

    private static void CustomSort<T>(this IList<T> list, Comparison<T> comparison)
    {
        // some custom implementation
    }
}

In this case, the code you posted would throw a StackOverflowException.


Original answer:

Perhaps Accounts is an object of a custom collection class whose Sort method calls itself?

public class AccountCollection : IEnumerable<Account> {
    // ...
    public void Sort(Comparison<Account> comparison) {
        Sort(comparison); // infinite recursion
    }
    // ...
}

Perhaps the AccountId property calls itself?

public class Account {
    // ...
    public string AccountId {
        get { return AccountId; } // infinite recursion
    }
    // ...
}
Dan Tao
+2  A: 

StackOverflowExceptions usually happen when you have a recursive call that goes wild. Check to see if either Sort or AccountId are calling themselves. If so, check the base-cases for those recursive functions and make sure they're stopping when they're supposed to stop.

Skrud
+5  A: 

Look at the callstack and you will see which function is executed over and over again. If this is not possible (because it is running inside a production environment for example), give more info.

about what the called properties call, where this function is called, etc

Henri
+4  A: 

If AccountId does something non-trivial (anything except access a local field) then that is the most likely bet.

An interesting fact is that technically Sort requires the ordering to be transitive, and string comparison is not always transitive! But this would rarely cause a stackoverflow (unless the Sort method uses some kind of FP approach); it might cause it to run forever, but I believe the inbuilt types even have this covered (they check for the theoretical max run-length and abort, IIRC).

I would be looking at AccountId; if it does something "clever" (like lazy-load some value from a parent collection), odds are the bug is in the "clever".

Marc Gravell
The transitive bug appears to be fixed in .Net 4.0
BlueRaja - Danny Pflughoeft
@BlueRaja - really? I haven't retried it - hang on...
Marc Gravell
@BlueRaja - you're right! Thanks for the spot.
Marc Gravell
+4  A: 

So I had a tricky situation where I was getting StackOverflow exceptions in a comparison method.

My comparison method:

public bool Equals(Type rhs)
{
    if (rhs == null) return false;
    if (this == rhs) return true;

    return this.randomField.Equals(rhs.randomField);
}

My operator:

public static bool operator ==(Type lhs, Type rhs)
{
    if (lhs == null)
        return (rhs == null);
    else
        return lhs.Equals(rhs);
}

So, what had happened was the == operator was calling the Equals method, which was then calling the == operator when it ran the line this == rhs. The solution was to convert the line to Object.ReferenceEquals(this, rhs).

jdmichal
He's comparing strings, though...
Dan Tao
The question edit made it in after I had started writing my post. Obviously there would not be such a problem with strings.
jdmichal
+2  A: 

Just because THIS line is throwing the StackOverflow doesn't mean that it's the cause of the problem, e.g.

void methodA()
{
   b();
   methodA();
}

This is as likely to get a stack overflow on b() as it is on the recursive call to methodA();

I suspect the recursion is on the method around this line of code.

Hightechrider