C# - Система. StackOverflowException с лямбдой

Под тем, какие ситуации были бы эта ошибка в коде с Системой. StackOverflowException?

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

Обновление:
свойство записано как:

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

Ничто специальное продолжение вообще. Вид не переопределяется также.

7
задан egrunin 10 May 2010 в 20:06
поделиться

6 ответов

Посмотрите на стек вызовов и вы увидите, какая функция выполняется снова и снова. Если это невозможно (например, потому что программа работает в производственной среде), предоставьте больше информации.

о том, какие вызываемые свойства вызывают, где вызывается эта функция и т.д.

5
ответ дан 6 December 2019 в 07:50
поделиться

Вот необычная идея:

Аккаунты объявлены как List ?

Мне интересно, является ли Accounts свойством, объявленным как нечто иное, чем List - например, как IList - и у вас где-то есть статический вспомогательный класс с методом расширения Sort , который не реализован должным образом. Это может попытаться использовать метод List .Sort , когда переданный параметр представляет собой List , но сделать это без выполнения необходимого преобразования в List , что приводит к гарантированному StackOverflowException .

Я имею в виду вот что. Предположим, что Account является свойством некоторого класса, который выглядит примерно так:

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>();
    }
}

А затем предположим, что где-то еще у вас есть этот статический класс с методом расширения Sort :

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
    }
}

В этом случае , опубликованный вами код вызовет исключение StackOverflowException .


Исходный ответ:

Возможно, Accounts является объектом пользовательского класса коллекции, чей метод Sort вызывает сам себя?

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

Возможно, свойство AccountId называет себя?

public class Account {
    // ...
    public string AccountId {
        get { return AccountId; } // infinite recursion
    }
    // ...
}
4
ответ дан 6 December 2019 в 07:50
поделиться

Итак, у меня была сложная ситуация, когда я получал исключения StackOverflow в методе сравнения.

Мой метод сравнения:

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

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

Мой оператор:

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

Итак, произошло следующее: оператор == вызывал метод Equals, который затем вызывал оператор == при выполнении строки this == rhs. Решением было преобразовать строку в Object.ReferenceEquals(this, rhs).

5
ответ дан 6 December 2019 в 07:50
поделиться

StackOverflowException обычно происходит, когда у вас есть рекурсивный вызов, который выходит из-под контроля. Проверьте, не вызывают ли Sort или AccountId сами себя. Если да, проверьте базовые случаи для этих рекурсивных функций и убедитесь, что они останавливаются, когда должны остановиться.

2
ответ дан 6 December 2019 в 07:50
поделиться

Если AccountId делает что-то нетривиальное (что угодно, кроме доступа к локальному полю), то это наиболее вероятная ставка.

Интересный факт: технически Sort требует, чтобы упорядочивание было транзитивным, а сравнение строк не всегда транзитивно! Но это редко вызывает переполнение стека (если только метод Sort не использует какой-нибудь FP-подход); это может привести к вечному выполнению, но я полагаю, что встроенные типы даже покрывают это (они проверяют теоретическую максимальную длину выполнения и прерывают, IIRC).

Я бы посмотрел на AccountId; если он делает что-то "умное" (например, лениво загружает какое-то значение из родительской коллекции), скорее всего, ошибка в этом "умном".

5
ответ дан 6 December 2019 в 07:50
поделиться

Тот факт, что ЭТА строка вызывает StackOverflow, не означает, что это причина проблемы, например

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

Вероятность переполнения стека в b () такая же, как и при рекурсивном вызове methodA ();

Я подозреваю, что рекурсия связана с методом в этой строке кода.

2
ответ дан 6 December 2019 в 07:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: