Lambda表达奇怪

时间:2011-01-11 15:36:57

标签: c# lambda operator-precedence

长话短说。我有2个包含相同类型的列表(但用于不同的东西),我想知道EITHER列表是否包含具有特定名称的项目。

我的原始代码完全有效:

if (listA.Any(var => var.Name == strMatch) || listB.Any(var => var.Name == strMatch))
{
    //Do something
}

此代码完美无缺,无论该项目是否存在于任一列表或两个列表中。 后来,我发生了几次'不可能'的崩溃 - 这些事情本来就不会发生。 我追溯到如果声明永远不会返回true。

这困扰了我多年......我无法解决出了什么问题。最终我放弃并粘贴在lamda表达式的主体周围,如此......

if (listA.Any(var => (var.Name == strMatch)) || listB.Any(var => (var.Name == strMatch)))
{
    //Do something
}

重新运行程序后,所有“不可能”的错误都消失了,它正常运行。删除额外的支持会导致错误再次出现。

我之前从未遇到过lambda表达式的问题(特别是在它们正常工作的情况下,然后在几次运行正常工作之后)并且我的其他lambda表达式正常工作。

示例:以下代码按预期工作100%(假设其中一个列表中存在匹配项)

Item item =
    ListA.FirstOrDefault(var => var.Name == strMatch) ??
    ListB.FirstOrDefault(var => var.Name == strMatch);

发生了什么事?为什么编译器对某些 lamda表达式而不是其他表达式挑剔? (即使它们完全相同?)

更新::系统详情 使用Microsoft Visual Studio 2008(专业版),Windows Vista 32位。

更新 Video link,这已经在其他计算机上进行了测试, NOT 可重现。让我觉得我的电脑注定失败了。重新安装VS无效。

请忽略任何背景猫声,当她听到我录制的东西时,她只会喵喵叫。

1 个答案:

答案 0 :(得分:3)

这些额外的括号不会改变那些lambda表达式的含义,也不会改变编译器如何选择编译这两个不同的代码块。根据您提供的内容,您的两个选择之间似乎没有功能差异,因此问题与括号内容无关。

修改

所以我创建了一个快速类,它完全按照你的说法完成,而IL只在类名中有所不同。我使用ildasmwindiff来确认这一点。它也不会因/optimize-/debug:full而改变。

  .method /*06000005*/ public hidebysig 
          instance bool  '<Main>b__3'(class [mscorlib/*23000001*/]System.Tuple`2/*01000006*/<int32,string> var) cil managed
  // SIG: 20 01 02 15 12 19 02 08 0E
  {
    // Method begins at RVA 0x207c
    // Code size       22 (0x16)
    .maxstack  2
    .locals /*11000001*/ init ([0] bool CS$1$0000)
-   .line 29,29 : 69,92 ''
+   .line 29,29 : 67,88 ''
-   //000029:       if (listA.Any(var => (var.Item2 == strMatch)) || listB.Any(var => (var.Item2 == strMatch)))
+   //000029:       if (listA.Any(var => var.Item2 == strMatch) || listB.Any(var => var.Item2 == strMatch))
    IL_0000:  /* 03   |                  */ ldarg.1
    IL_0001:  /* 6F   | (0A)000005       */ callvirt   instance !1 class [mscorlib/*23000001*/]System.Tuple`2/*01000006*/<int32,string>/*1B000001*/::get_Item2() /* 0A000005 */
    IL_0006:  /* 02   |                  */ ldarg.0
-   IL_0007:  /* 7B   | (04)000001       */ ldfld      string Parentheses/*02000002*//'<>c__DisplayClass6'/*02000003*/::strMatch /* 04000001 */
+   IL_0007:  /* 7B   | (04)000001       */ ldfld      string NoParentheses/*02000002*//'<>c__DisplayClass6'/*02000003*/::strMatch /* 04000001 */
    IL_000c:  /* 28   | (0A)000006       */ call       bool [mscorlib/*23000001*/]System.String/*01000007*/::op_Equality(string, string) /* 0A000006 */
    IL_0011:  /* 0A   |                  */ stloc.0
    IL_0012:  /* 2B   | 00               */ br.s       IL_0014

Nota bene:生成了其中两个,每个listX.Any个调用一个。两者的评论都不同。生成的IL是相同的。

编辑2:

ildasm对于Visual Studio 2008(csc 3.5.30729.4926)的输出也没有什么不同,所以我真的无法说出为什么在你的VS2k8实例中除了LINQ版本之外它还会死被窃听或该机器上的编译器有一个错误的表达式生成器,因为我无法复制任何差异。