Под тем, какие ситуации были бы эта ошибка в коде с Системой. StackOverflowException?
Accounts.Sort((x, y) => string.Compare(x.AccountId, y.AccountId));
Обновление:
свойство записано как:
public string AccountId
{
get { return _accountId; }
set { _accountId = value; }
}
Ничто специальное продолжение вообще. Вид не переопределяется также.
Посмотрите на стек вызовов и вы увидите, какая функция выполняется снова и снова. Если это невозможно (например, потому что программа работает в производственной среде), предоставьте больше информации.
о том, какие вызываемые свойства вызывают, где вызывается эта функция и т.д.
Аккаунты объявлены как List
?
Мне интересно, является ли Accounts
свойством, объявленным как нечто иное, чем List
- например, как IList
- и у вас где-то есть статический вспомогательный класс с методом расширения Sort
, который не реализован должным образом. Это может попытаться использовать метод List
, когда переданный параметр представляет собой 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
}
// ...
}
Итак, у меня была сложная ситуация, когда я получал исключения 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)
.
StackOverflowException
обычно происходит, когда у вас есть рекурсивный вызов, который выходит из-под контроля. Проверьте, не вызывают ли Sort
или AccountId
сами себя. Если да, проверьте базовые случаи для этих рекурсивных функций и убедитесь, что они останавливаются, когда должны остановиться.
Если AccountId
делает что-то нетривиальное (что угодно, кроме доступа к локальному полю), то это наиболее вероятная ставка.
Интересный факт: технически Sort
требует, чтобы упорядочивание было транзитивным, а сравнение строк не всегда транзитивно! Но это редко вызывает переполнение стека (если только метод Sort
не использует какой-нибудь FP-подход); это может привести к вечному выполнению, но я полагаю, что встроенные типы даже покрывают это (они проверяют теоретическую максимальную длину выполнения и прерывают, IIRC).
Я бы посмотрел на AccountId
; если он делает что-то "умное" (например, лениво загружает какое-то значение из родительской коллекции), скорее всего, ошибка в этом "умном".
Тот факт, что ЭТА строка вызывает StackOverflow, не означает, что это причина проблемы, например
void methodA()
{
b();
methodA();
}
Вероятность переполнения стека в b () такая же, как и при рекурсивном вызове methodA ();
Я подозреваю, что рекурсия связана с методом в этой строке кода.