【问题标题】:Why do I get Stackoverflow Exception when calling ToList (after orderBy) on IEnumerable?为什么在 IEnumerable 上调用 ToList(在 orderBy 之后)时出现 Stackoverflow 异常?
【发布时间】:2015-10-02 09:41:15
【问题描述】:

我有一段导致堆栈溢出异常的 LINQ 代码,我不知道为什么。我将保持代码不变,因为我不知道哪个部分是原因。

假设我们有一个预订记录列表:

Class BookRecords
    Public START_DATE As String
    Public END_DATE As String
    Public BOOK_NUM As String
End Class

任务是找出所有记录(1)开始时间在从现在开始的15分钟内和(2)与(1)中的记录连续。

我是这样做的:

Private Function ValidRec(RecordList As List(Of BookRecords)) As List(Of BookRecords)
    Dim timeNow = Date.Now
    'Valid records by itself
    Dim validRecords = RecordList.Where(
        Function(r)
            Dim startDate As DateTime
            'VVVVV stack overflow thrown at this return
            Return DateTime.TryParse(r.START_DATE, startDate) AndAlso
                   ((startDate - timeNow).TotalMinutes < 15)
        End Function)

    Do
        'consecutive records
        Dim conseRecords = RecordList.Except(validRecords).Where(
                            Function(r) validRecords.Any(
                            Function(vr) vr.END_DATE.Equals(r.START_DATE)))

        If Not conseRecords.Any() Then Exit Do
        validRecords = validRecords.Concat(conseRecords.Except(validRecords))
    Loop

    validRecords = validRecords.OrderBy(Function(vr) vr.START_DATE) _
                               .ThenBy(Function(vr) vr.BOOK_NUM)

    'stack overflow after the ToList line 
    Return validRecords.ToList
End Function

代码在最后一行validRecords.ToList 之后运行良好。然后在 Return DateTime.TryParse ... 语句中发生堆栈溢出。 RecordList 和 validRecords 的大小很小(测试中均为 2 个),并且没有其他线程修改这些列表/对象。

为什么这会用完堆栈?我知道 LINQ 语句的结构可能很糟糕,并且不必要地创建了很多列表(IEnumerables?),但这是原因吗? (那将是真正的堆栈溢出,酷)

我认为将 validRecords 设为列表而不是 IEnumerable 可以避免该问题,但如果有人能指出真正的原因,我将不胜感激。

【问题讨论】:

    标签: vb.net linq sql-order-by ienumerable


    【解决方案1】:

    显然,您对这些 LINQ 方法的作用有错误的理解。每当您调用.Where().Except() 等时,都会创建一个新的枚举器。此枚举器仅保存其特征(例如,Where 枚举器保存其谓词)。查询尚未执行。它仅在需要数据时执行,例如当您在枚举器上调用 ToList() 时。这就是为什么这里是抛出异常的地方。

    在您的具体示例中,问题是由OrderBy 函数引起的。看起来,它创建了一个无限枚举。但是,我不知道为什么。一定是一些讨厌的实现细节。

    无论如何。强迫 LINQ 解决这个问题是错误的方法。以经典方式实现它更有效,更容易。这使您可以明确指定如何使用加速数据结构(例如HashSetsDictionaries)以及数据的排序时间和频率。由于其本地范围,所有 LINQ 枚举器都必须在需要时重新创建此结构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多