Лямбда-выражение странность - PullRequest
4 голосов
/ 11 января 2011

Короче говоря. У меня есть 2 списка, которые содержат один и тот же тип (но используются для разных целей), и я хочу знать, содержит ли ЛИБО список с определенным именем.

Мой оригинальный код, который работал идеально, был:

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
}

После перезапуска моей программы все «невозможные» ошибки исчезли и работали нормально. Удаление лишних защитных слоев приводит к появлению ошибок.

Раньше у меня никогда не было этой проблемы с лямбда-выражениями (особенно там, где они работают и ТО, после того, как несколько прогонов работают некорректно), а остальные лямбда-выражения работают правильно.

Пример: следующий код работает на 100%, как и ожидалось (при условии совпадения в одном из списков)

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

Что происходит? Почему компилятор требователен к некоторым выражениям lamda, а не к другим? (Даже когда они идентичны?) ???

ОБНОВЛЕНИЕ :: Сведения о системе Это встречалось с Microsoft Visual Studio 2008 (Professional), Windows Vista 32bit.

UPDATE Ссылка на видео , это было проверено на других компьютерах и НЕ воспроизводимо. Заставляет меня чувствовать, что мой компьютер обречен. Переустановка VS не имеет никакого эффекта.

Пожалуйста, игнорируйте любые фоновые кошачьи шумы, она много мяукает, только когда слышит, как я что-то записываю.

1 Ответ

3 голосов
/ 11 января 2011

Эти дополнительные скобки не меняют значения этих лямбда-выражений, а также того, как компилятор выбирает компилировать эти два разных блока кода. Судя по тому, что вы указали, между вашими двумя вариантами выбора нет никакой функциональной разницы, поэтому проблема не связана с круглыми скобками.

EDIT:

Итак, я создал быстрый класс, который делает именно то, что вы заявили, и IL отличается только именами классов. Я использовал ildasm и windiff, чтобы подтвердить это. Не меняется и с /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

Примечание: существует два из них, по одному для каждого из вызовов listX.Any. Оба отличаются только в своих комментариях. Сгенерированный IL идентичен.

РЕДАКТИРОВАТЬ 2:

Вывод ildasm для Visual Studio 2008 (csc 3.5.30729.4926) также ничем не отличается, поэтому я действительно не могу сказать, почему в вашем экземпляре VS2k8 он умирает, кроме, возможно, версии LINQ, которая у вас прослушивается или компилятор на этой машине имеет генератор выражений с ошибками, потому что я не могу воспроизвести разницу.

...