Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Definition of "Equals" for empty arrays and difference between .NET and .NET core

I have written some unit tests yesterday that pass in .NET 4.6.1 but fail in .NET core 3.0 because the number of array instances that is generated during that test is different in both environments. After some investigation it turned out that the count of empty arrays created with LINQ is different. I was finally able to dump it down to this test:

    [Test]
    public void ArrayTest()
    {
        var numbers = Enumerable.Range(1, 5);

        int[] items1 = numbers.Where(i => i > 5).ToArray();
        int[] items2 = numbers.Where(i => i > 5).ToArray();

        Assert.IsFalse(items1 == items2);      // fails in .NET core 3 but passes in .NET 461
        Assert.IsFalse(items1.Equals(items2)); // fails in .NET core 3 but passes in .NET 461
    }

My question is: does anyone know where the implementation is different? Does ToArray() maybe return an Array.Empty<> singleton instance in .NET core but not in .NET if the collection has no elements?

like image 685
Döharrrck Avatar asked Apr 30 '20 09:04

Döharrrck


1 Answers

Does ToArray() maybe return an Array.Empty<> singleton instance in .NET core but not in .NET if the collection has no elements?

Yes. Linq was given a lot of speed optimizations in .NET Core.

In .NET Framework, Enumerable.ToArray() calls Buffer<TElement>.ToArray(), which returns a new TElement[0] if the buffer is empty.

In .NET Core, for your specific case of <array>.Where(...).ToArray(), Enumerable.ToArray() calls IIListProvider<TSource>.ToArray(), which is implemented by WhereArrayIterator<TSource>.ToArray(), which calls new LargeArrayBuilder<TSource>(_source.Length), which uses Array.Empty<T>.

like image 152
canton7 Avatar answered Oct 23 '22 05:10

canton7