调试 LINQ

Visual Studio 支持语言集成查询 (LINQ) 代码调试,但是有一些限制。大多数调试功能都适用于 LINQ 语句,包括单步执行、设置断点以及在调试器窗口中查看结果。 本主题介绍 LINQ 调试的主要限制。

主题内容

Viewing LINQ Results

介绍在调试器中查看 LINQ 查询结果时要考虑的特殊情况。

Stepping and LINQ

解释 LINQ 调试过程中的单步执行行为。

Edit and Continue Not Supported for LINQ

解释在调试期间尝试编辑 LINQ 代码时预料可以看到的行为。

查看 LINQ 结果

使用数据提示功能、“监视”窗口和“快速监视”对话框,可以查看 LINQ 语句的结果。 在使用源窗口时,可以将指针停放在源窗口中的某个查询上,这样会出现“数据提示”。 可以将一个 LINQ 变量复制并粘贴到“监视”窗口或“快速监视”对话框中。

在 LINQ 中,查询不会在创建或声明时进行计算,而只在使用时才进行计算。 因此,查询经过计算后才具有值。 有关查询创建和计算的完整说明,请参见 LINQ 查询简介 (C#)编写第一个 LINQ 查询 (Visual Basic)

若要显示某个查询的结果,调试器必须计算该查询。 在调试器中查看 LINQ 查询结果时,这种隐式计算具有的某些影响,应当加以考虑:

  • 查询的每次计算都需要时间。 展开结果节点需要时间。 对于某些查询,反复计算可能导致性能显著下降。

  • 计算查询可能产生副作用,这些副作用表现为对数据的值或程序状态的更改。 不是所有查询都具有副作用。 若要确定查询是否可以安全计算而不具有副作用,必须理解实现查询的代码。

单步执行和 LINQ

在调试 LINQ 代码时,单步执行具有一些您应该知道的行为差异。

Bb385795.collapse_all(zh-cn,VS.110).gifLINQ to SQL

在 LINQ to SQL 查询中,谓词代码不受调试器控制。 因此,无法进入并单步执行谓词代码。 任何编译为表达式树的查询都会产生不受调试器控制的代码。

Bb385795.collapse_all(zh-cn,VS.110).gifVisual Basic 中的单步执行

在单步执行 Visual Basic 程序且调试器遇到查询声明时,调试器不会进入并单步执行该声明,而是将整个声明作为单个语句突出显示。 发生此行为的原因是查询直到调用时才进行计算。 有关更多信息,请参见 Visual Basic 中的 LINQ 简介

如果单步执行下面的代码示例,则调试器会将查询声明或查询创建作为单个语句突出显示。

Function MyFunction(ByVal x As Char)
    Return True
End Function

Sub Main()
    'Query creation
    Dim x = From it In "faoaoeua" _
            Where MyFunction(it) _
            Select New With {.a = it}

    ' Query execution
    For Each cur In x
        Console.WriteLine(cur.ToString())
    Next
End Sub

当您再次单步执行时,调试器会突出显示 For Each cur In x。 在下一步中,调试器会进入并单步执行函数 MyFunction。 在单步执行 MyFunction 后,调试器跳回到 Console.WriteLine(cur.ToSting())。 调试器在任何时候都不会单步执行查询声明中的谓词代码,尽管调试器的确会计算该代码。

Bb385795.collapse_all(zh-cn,VS.110).gif用函数替换谓词以启用单步执行 (Visual Basic)

如果必须单步执行谓词代码以便达到调试目的,则可以将谓词替换为对包含原始谓词代码的函数的调用。 例如,假定您具有下面的代码:

Dim items() as integer ={1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

' Get the even numbers
Dim query = From nextInt in items Where nextInt Mod 2 = 0 Select nextInt

For each item in query
      Console.WriteLine(item)
Next

可以将谓词代码移动至一个新函数,该函数称为 IsEven:

Dim items () as integer ={1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

' Get the even numbers
Dim query = From nextInt in items Where IsEven(nextInt) Select nextInt

For each item in query
      Console.WriteLine(item)
Next
... 
Function IsEven(item As =Integer) as Boolean
      Return item Mod 2 = 0
End Function

修改后的查询在每次遍历 items 时都会调用函数 IsEven。 您可以使用调试器窗口来查看每个“item”是否满足指定条件,并且可以单步执行 IsEven 中的代码。 此示例中的谓词相当简单。 但是,如果必须调试一个更复杂的谓词,这种技术也会十分有用。

" 编辑并继续 " 不支持 LINQ

“编辑并继续”不支持对 LINQ 查询的更改。 如果在调试会话过程中添加、移除或更改 LINQ 语句,则会出现一个对话框,告知您“编辑并继续”不支持该更改。 此时,可以撤消更改,或停止调试会话并对编辑的代码重新启动新会话。

此外,“编辑并继续”不支持更改 LINQ 语句中使用的变量的类型或值。 同样,可以撤消更改,或停止并重新启动调试会话。

在 C# 中,不能对包含 LINQ 查询的方法中的任何代码使用“编辑并继续”。

在 Visual Basic 中,可以对非 LINQ 代码使用“编辑并继续”,即使是在包含 LINQ 查询的方法中,也是如此。 在 LINQ 语句前,可以添加或移除代码,即使这些更改会影响 LINQ 查询的行号,也是如此。 非 LINQ 代码的 Visual Basic 调试体验与引入 LINQ 前是一样的。 但是,除非要停止调试以应用更改,否则不能更改、添加或移除 LINQ 查询。

请参见

概念

副作用与表达式

异常处理(调试)

LINQ 查询简介 (C#)

Visual Basic 中的 LINQ 简介

其他资源

Debugging SQL

调试准备:SQL Server 项目