Since .NET version something we now have an implicit cast from string
-> ReadOnlySpan<char>
. This means that if a function accepts a ReadOnlySpan<char>
, we can just pass it a string and the "conversion" will happen automatically.
This implicit operator is not available in .NET Standard 2.0 nor in .NET Framework though... We are working with all three :)
Basically I have this field in my ref struct
private readonly ReadOnlySpan<char> _defaultDelimiters = new[] { ' ', ';' };
I use this field every time a function called Read()
is called. The alternative would be to remove this field and put a stackalloc
inside Read()
. But I do not know if that is wise or not
To make my .NET code compliant with .NET Standard 2.0 and Framework I could simply add .AsSpan()
calls to my strings. This is however "unnecessary" in .NET (Core) but my question is: Is it also performance wise worse? Or do the .AsSpan()
extension and the implicit operator perform the same operation behind the scenes anyway?
As you can see from the source code, the following code is executed for the implicit
operator:
public static implicit operator ReadOnlySpan<char>(string? value) =>
value != null ? new ReadOnlySpan<char>(ref value.GetRawStringData(), value.Length) : default;
The extension method does this
public static ReadOnlySpan<char> AsSpan(this string? text)
{
if (text == null)
return default;
return new ReadOnlySpan<char>(ref text.GetRawStringData(), text.Length);
}
So effectively the exact same code. There is absolutely no difference in performance between these. (Possibly a small difference in branch prediction due to the opposite order of the conditions).
No, there is no heap allocation. A Span
and a ReadOnlySpan
are ref struct
so they can't be allocated on the heap even if you tried (like boxing them), it's not allowed.
Assuming the char
array is static
(or a string
is coming from a constant value), probably you are already using the most efficient allocation method. It doesn't need to reserve any stack space, it can just take a Span
off the existing array.
Whereas stackalloc
means you need to copy the data into it every time. And stackalloc
can also have serious implications when used in a loop, often causing a stack overflow.
If the char
array is not static (eg you are feeding new[]
straight into the initializer/constructor) then that is going to be even more inefficient. Keep the array static
in a separate field, or just use a constant string
value.