代码之家  ›  专栏  ›  技术社区  ›  BuddyJoe

C-System.StackOverflowException with lambda

  •  7
  • BuddyJoe  · 技术社区  · 14 年前

    在什么情况下,此代码会因System.StackOverflowException出错?

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

    更新 :
    财产写为:

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

    没什么特别的。排序也不会被重写。

    6 回复  |  直到 14 年前
        1
  •  5
  •   Henri    14 年前

    查看调用堆栈,您将看到一次又一次执行哪个函数。如果这是不可能的(例如,因为它在生产环境中运行),请提供更多信息。

    关于被调用的属性调用的内容、调用该函数的位置等

        2
  •  5
  •   Marc Gravell    14 年前

    如果 AccountId 做一些不平凡的事( 任何东西 除了访问一个本地字段),这是最有可能的赌注。

    一个有趣的事实是 技术上 Sort 要求顺序是可传递的,字符串比较是 not always transitive !但这很少会导致stackoverflow(除非 排序 方法使用某种fp方法);它 可以 使它永远运行,但我相信内置类型甚至涵盖了这一点(它们检查理论上的最大运行长度和中止,IIRC)。

    我会看着 记帐 ;如果它做了一些“聪明”的事情(比如懒惰地从父集合中加载一些值),那么很可能bug就在“聪明”中。

        3
  •  5
  •   jdmichal    14 年前

    所以我遇到了一个棘手的情况,我在比较方法中得到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) .

        4
  •  4
  •   Dan Tao    14 年前

    下面是一个现成的想法:

    是帐户 宣布 作为 List<Account> ?

    我想知道 Accounts 财产是否声明为 列出<帐户> --例如,作为 IList<Account> --在某个地方有一个静态助手类, Sort 未正确实现的扩展方法。这可能试图利用 List<T>.Sort 当传入的参数是 List<T> 但不执行必要的强制转换 列表& 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>();
        }
    }
    

    然后假设在其他地方有一个静态类, 排序 扩展方法:

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

    在这种情况下,您发布的代码将 栈溢出异常 .


    原始答案:

    也许 账户 是自定义集合类的对象,其 排序 方法调用自身?

    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
        }
        // ...
    }
    
        5
  •  2
  •   Skrud    14 年前

    StackOverflowException s通常发生在递归调用失控时。检查是否 Sort AccountId 在呼唤自己。如果是这样,请检查这些递归函数的基本情况,并确保它们在应该停止时停止。

        6
  •  2
  •   Ian Mercer    14 年前

    仅仅因为这一行抛出了stackoverflow并不意味着这就是问题的原因,例如。

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

    这与对methoda()的递归调用一样,可能会在b()上发生堆栈溢出;

    我怀疑递归是围绕这行代码的方法。