【问题标题】:Warning: "Using the iteration variable in a lambda expression may have unexpected results"警告:“在 lambda 表达式中使用迭代变量可能会产生意外结果”
【发布时间】:2011-08-29 10:57:02
【问题描述】:

编辑:下面是这个问题的一个更简单的例子(我有deleted我原来的问题):

Dim numbers1 As New List(Of Int32)({1, 2, 3})
Dim numbers2 As New List(Of Int32)({3, 4, 5})
For Each n1 In numbers1
    ' no warning '
    Dim contains = numbers2.Contains(n1)
Next
For Each n1 In numbers1
    ' warning on n1'
    Dim contains = (From num In numbers2 Where num = n1).Any
Next

所以我仍然不明白为什么编译器认为我可能会在第二次迭代中得到意想不到的结果,而我在第一次迭代中是安全的。我不认为@ee-m 的interesting link 提供了这种行为的原因,(这不是for-each 问题,For n1 As Int32 = 1 To 3 也会导致编译器警告)。

我不太相信以下应该是“最佳实践”:

For Each n1 In numbers1
    Dim number1 = n1
    ' no warning'
    Dim contains = (From num In numbers2 Where num = number1).Any
Next

局部变量number1 是多余的,并且正如@Meta-Knight 已经强调的那样使代码的可读性降低。注意:这三种方式都是安全的,并且给出了正确的结果。

【问题讨论】:

    标签: .net vb.net linq compiler-construction linq-to-dataset


    【解决方案1】:

    Eric Lippert 就该主题写了几篇博文(代码示例使用 C#,而不是 VB),其中讨论了此类代码可能产生的一些“陷阱”,您可能会觉得有趣:

    Closing over the loop variable considered harmful

    【讨论】:

    • 确实很有趣。在 C# 中没有这样的警告。用 Lippert 的话来说:“警告正确行为的警告是非常糟糕的警告”。
    • +1 个有趣的链接。也许我误解了 eric 的观点,但即使我用For n1 As Int32 = 1 To 3 替换 for-each 循环,问题也是一样的。那么variable's scope be the body of the loop不应该吗?
    • @Tim Schmelter:简单的 for 循环也会出现完全相同的问题。请记住,C# 和 VB 之间存在差异。在 VB 中,您无论如何都不能在循环之外引用循环变量。但这并没有改变同一个变量在一次迭代中被重用到下一次的事实。
    【解决方案2】:

    正如消息所述,它“可能”产生不良影响。在您的情况下,.ToList() 使其安全,但这对于编译器来说很难验证。

    我建议采用复制到本地 var (Dim exc = excel) 作为标准“最佳实践”

    【讨论】:

    • 为什么编译器很难验证?我会理解 LINQ-Query 无法知道它将立即执行,因为 ToList 超出了它的上下文。但是无法更改迭代变量,因为此时它已经执行了。我假设编译器知道这一点,因此他可以将迭代变量“硬分配”到查询中。但我已采纳您的建议,将其复制到局部变量中。
    • 编译器构建器的 Why 部件 ID。但他们应该回溯多远?在这里,我们可以很快看到 AllExcelFiles 是一个 List(Of T),但通常它是一个 IEnumerable(Of T)。我想警告算法的范围仅限于 ForEach。
    • 这样做的问题是“Dim exc = excel”这一行完全是多余的,并且使代码不太清晰,所以我不知道我们是否真的可以称之为“最佳实践”。我正在考虑自己隐藏此警告消息,因为在这种情况下有很多误报。
    • @meta- 多余的:是的,不太清楚:不一定。随便取个好听的名字。这是关于提前思考,更改为 Parallel.ForEach 并且您真的需要它。
    • 很难为一个指向与循环变量完全相同的对象的变量找到一个好名字。因此,您要么使用缩写词,这会使代码不那么清晰,要么添加一个多余的形容词,如“currentExcel”或“excel2”,这也会造成混淆。你对命名这样一个变量有什么建议吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-01
    • 2013-08-05
    • 1970-01-01
    • 2010-09-18
    相关资源
    最近更新 更多