简体   繁体   English

C# - 使用Lambda的System.StackOverflowException

[英]C# - System.StackOverflowException with Lambda

Under what situations would this code error out with System.StackOverflowException? 在什么情况下,这个代码会出现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. 排序也不会被覆盖。

Look at the callstack and you will see which function is executed over and over again. 查看callstack,您将看到一遍又一遍地执行哪个函数。 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 关于被调用的属性调用什么,调用此函数的位置等

If AccountId does something non-trivial ( anything except access a local field) then that is the most likely bet. 如果AccountId做了一些非平凡的事情 (除了访问本地字段之外的任何事情 ),那么这是最有可能的赌注。

An interesting fact is that technically Sort requires the ordering to be transitive, and string comparison is not always transitive ! 一个有趣的事实是技术上 Sort要求排序是可传递的,字符串比较并不总是传递的 But this would rarely cause a stackoverflow (unless the Sort method uses some kind of FP approach); 但这很少会导致堆栈溢出(除非Sort方法使用某种FP方法); 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). 可能导致它永远运行,但我相信内置类型甚至覆盖了它们(它们检查理论上的最大游程长度和中止,IIRC)。

I would be looking at AccountId ; 我会看看AccountId ; if it does something "clever" (like lazy-load some value from a parent collection), odds are the bug is in the "clever". 如果它做了“聪明”的事情(比如从父集合中延迟加载某些值),那么错误就在于“聪明”。

So I had a tricky situation where I was getting StackOverflow exceptions in a comparison method. 所以我遇到了一个棘手的情况,我在比较方法中得到了StackOverflow异常。

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 . 所以,发生了什么是==运算符调用Equals方法,然后在运行this == rhs的行时调用==运算符。 The solution was to convert the line to Object.ReferenceEquals(this, rhs) . 解决方案是将该行转换为Object.ReferenceEquals(this, rhs)

Here's an off-the-wall idea: 这是一个彻头彻尾的想法:

Is Accounts declared as List<Account> ? 帐户是否声明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. 我想知道如果Accounts是一个声明为List<Account>之外的属性 - 例如,作为IList<Account> - 并且你有一个静态助手类,其中某个地方的Sort扩展方法没有正确实现。 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 . 当传入的参数是List<T> ,这可能会尝试利用List<T>.Sort方法,但这样做不会对List<T>执行必要的强制转换,从而导致保证StackOverflowException

What I mean is this. 我的意思是这个。 Suppose Account is a property of some class that looks something like this: 假设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>();
    }
}

And then suppose elsewhere you have this static class with a Sort extension method: 然后假设在其他地方你有这个带有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
    }
}

In this case, the code you posted would throw a StackOverflowException . 在这种情况下,您发布的代码将抛出StackOverflowException


Original answer: 原始答案:

Perhaps Accounts is an object of a custom collection class whose Sort method calls itself? 也许Accounts是自定义集合类的对象,其Sort方法调用自身?

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

Perhaps the AccountId property calls itself? 也许AccountId属性调用自己?

public class Account {
    // ...
    public string AccountId {
        get { return AccountId; } // infinite recursion
    }
    // ...
}

StackOverflowException s usually happen when you have a recursive call that goes wild. StackOverflowException通常发生在你有一个疯狂的递归调用时。 Check to see if either Sort or AccountId are calling themselves. 检查SortAccountId是否在调用自己。 If so, check the base-cases for those recursive functions and make sure they're stopping when they're supposed to stop. 如果是这样,检查这些递归函数的基本情况,并确保它们在它们应该停止时停止。

Just because THIS line is throwing the StackOverflow doesn't mean that it's the cause of the problem, eg 仅仅因为此行抛出StackOverflow并不意味着它是问题的原因,例如

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

This is as likely to get a stack overflow on b() as it is on the recursive call to methodA(); 这很可能在b()上获得堆栈溢出,因为它是对methodA()的递归调用;

I suspect the recursion is on the method around this line of code. 我怀疑递归是围绕这行代码的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM