I'm working on an internal library that needs to support both lists and arrays. This is a hot path so we're looking at performance improvements.
Currently it's using IList<T>
in the parameters, as we require index based access in the library, and to avoid re-writing it for both types.
public int Foo<T>(IList<T> values);
A pretty free performance improvement (measured and benchmarked) would be to convert it to a span internally, which we could do just by making some overloads that convert the value and pass it on immediately, but it feels like there should be a cleaner way. I'm not a big fan of having a lot of stubs, especially when it seems like they're doing a very similar thing.
public int Foo<T>(T[] values)
=> Foo(values.AsSpan());
public int Foo<T>(List<T> values)
=> Foo(CollectionsMarshal.AsSpan(values));
private int Foo<T>(Span<T> values)
Is there any interface/marshal that can be used for both a List and an Array that converts them to a Span?
There is no way of using the same AsSpan()
method for Lists and Arrays, other than creating your own AsSpan()
Extension. Instead you could always use IList<T>
:
public int Foo<T>(IList<T> list)
{
Span<T> span;
if (list is T[] array)
{
span = array.AsSpan();
}
else if (list is List<T> concreteList)
{
span = CollectionsMarshal.AsSpan(concreteList);
}
else
{
throw new NotSupportedException("not supported!");
}
return Foo(span);
}
private int Foo<T>(Span<T> values)
{
// ...
}