Description
When using collection expression targeted to IEnumerable<T>
to append a single item into something that also implements IEnumerable<T>
, I'd expect it being lowered into something at least as efficient as source.Concat([newObj]);
Instead it is lowered as creating new array, copying data into it, and wrapping that into compiler generated Readonlyarray.
using System.Collections.Generic;
public class C {
public void M(IReadOnlyList<object> source) {
IEnumerable<object> extendedState = [.. source, new()];
}
}
->
public class C
{
[NullableContext(1)]
public void M(IReadOnlyList<object> source)
{
int num = 0;
object[] array = new object[1 + source.Count];
IEnumerator<object> enumerator = source.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
object obj = (array[num] = enumerator.Current);
num++;
}
}
finally
{
if (enumerator != null)
{
enumerator.Dispose();
}
}
array[num] = new object();
num++;
new <>z__ReadOnlyArray<object>(array);
}
}
This seems rather unexpected. While allocations are unavoidable in this case, copying the whole - potentially super big enumerable - into an array seems avoidable.
It generally seems that collectoin expressions tagetting IEnumerable-like things prefer everything being backed by already realized memory instead of constructing LINQ.
As evident by changing type of the source: https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABADAAgwRhQG4BYAKAwGY8AmHAYRwG9yc29qMUcBZACgKUAPBGAArGGAAuAPhwBnCAFcoYGAEpmrdjsEjxk2ThgIpMAHYATGJYDKUgIZmcAXhwBtAHSeFy1TAAaHHMYAHc+dQBdUjIdAF9yOKA