Ответы с форумов MSDN

LINQ - LastOrDefault работает по другому в .NET Core

Date: 29.06.2019 14:27:41

Подобный результат можно воспроизвести, например, на https://dotnetfiddle.net при выборе .NET Core 2.2. Скорее всего, это просто баг. Какое окружение использует ваш "UnitTest"?

Message 222

Date: 29.06.2019 16:20:22

Тут все упирается в то, как работают Select и LastOrDefault. Возьмите следующий код:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        
        static void Main(string[] args)
        {
            var array = new int[] { 1, 2, 3 };
            var sel = array.Select((x) => { Console.WriteLine(x.ToString() + " selected"); return x; });
            var t = sel.GetType();

            Console.WriteLine("Select iterator type: "+t.ToString()+"\n");

            Console.WriteLine("Select iterator interfaces: ");
            Console.WriteLine(String.Join("\n", t.GetInterfaces().Select(x => x.ToString())));
            Console.WriteLine("\nLastOrDefault: "+sel.LastOrDefault());
            

        }
    }    
}

При запуске в .NET Framework он даст такой результат:

Select iterator type: System.Linq.Enumerable+WhereSelectArrayIterator`2[System.Int32,System.Int32]

Select iterator interfaces:
System.Collections.Generic.IEnumerable`1[System.Int32]
System.Collections.IEnumerable
System.Collections.Generic.IEnumerator`1[System.Int32]
System.IDisposable
System.Collections.IEnumerator
1 selected
2 selected
3 selected

LastOrDefault: 3

При запуске под .NET Core:

Select iterator type: System.Linq.Enumerable+SelectArrayIterator`2[System.Int32,System.Int32]

Select iterator interfaces: 
System.Collections.Generic.IEnumerable`1[System.Int32]
System.Collections.IEnumerable
System.Collections.Generic.IEnumerator`1[System.Int32]
System.IDisposable
System.Collections.IEnumerator
System.Linq.IPartition`1[System.Int32]
System.Linq.IIListProvider`1[System.Int32]
3 selected

LastOrDefault: 3

Как видно, в .NET Core результатом Select является совершенно другой тип, который реализует интерфейс IPartition. Метод LastOrDefault содержит оптимизацию, которая заставляет его, если тип итератора реализует IPartition, не вычислять всю последовательность, я сразу брать ее последний элемент (это видно, если в выражение Select поместить вывод). Таким образом, ваш код, который рассчитывал на вычисление всей последовательности, ломается.  



Автор: VadimTagil

Главная страница - Список тем - Репозиторий на GitHub