C # - System.StackOverflowException с лямбда-выражениями - PullRequest
7 голосов
/ 07 мая 2010

При каких ситуациях этот код ошибки с System.StackOverflowException?

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

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

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

Ничего особенного вообще не происходит. Сортировка также не отменяется.

Ответы [ 6 ]

5 голосов
/ 07 мая 2010

Итак, у меня была сложная ситуация, когда я получал исключения 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 голосов
/ 07 мая 2010

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

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

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

5 голосов
/ 07 мая 2010

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

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

4 голосов
/ 07 мая 2010

Вот нестандартная идея:

Является ли учетные записи объявленными как List<Account>?

Мне интересно, если Accounts - это свойство, объявленное как-то отличное от List<Account> - например, IList<Account> - и у вас есть где-то статический вспомогательный класс с методом расширения Sort, который не реализован должным образом.Это может попытаться использовать метод List<T>.Sort, когда переданный параметр является List<T>, но сделать это без выполнения необходимого приведения к List<T>, что приведет к гарантированному 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
    }
    // ...
}
2 голосов
/ 07 мая 2010

То, что в ЭТОЙ строке выбрасывается поток StackOverflow, не означает, что это является причиной проблемы, например,

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

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

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

2 голосов
/ 07 мая 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...