string.AsSpan() vs implicit cast operator peformance in .NET for ReadOnlySpan<char>

273 views Asked by At

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?

1

There are 1 answers

5
Charlieface On BEST ANSWER
  1. 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).

  2. 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.

  3. 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.