Search code examples
c#dry

Why ReadOnlySpan may not be used as a type argument for generic delegates and generic methods?


I understand why ReadOnlySpan may not be used as a type argument for generic classes. ReadOnlySpan is stack only and therefore it cannot be used as field types, field members live in the heap like its container object. However return values and arguments are always stack only, so why ReadOnlySpan cannot be used as type argument for generic delegates and generic methods?

Here you have an example illustrating what I'm saying:

using System;

namespace ConsoleApp7
{
    class Program
    {
        public delegate TResult MyFunc<TResult>(ReadOnlySpan<char> arg);

        static int GetSpanLength(ReadOnlySpan<char> span)
        {
            return span.Length;
        }

        static void Main(string[] args)
        {
            var span = "hello".AsSpan();

            MyFunc<int> func1 = GetSpanLength;
            var result1 = DoSomething(func1, span);

            // The type 'ReadOnlySpan<char>' may not be used as a type argument
            Func<ReadOnlySpan<char>, int> func2 = GetSpanLength;

            //The type 'ReadOnlySpan<char>' may not be used as a type argument
            var result = DoSomething<int, ReadOnlySpan<char>>(func2, span);


        }

        static TResult DoSomething<TResult, T>(Func<T, TResult> func, T arg)
        {
            return func(arg);
        }

        static TResult DoSomething<TResult>(MyFunc<TResult> func, ReadOnlySpan<char> arg)
        {
            return func(arg);
        }

    }
}

It's very unfortunate because it forces me to have two identical versions of DoSomething method, making my code very WET.

NOTE: for projects targeting .NET Framework you need to install System.Memory Nuget Package.


Solution

  • As of .NET 9, it is now possible to pass Spans using the new allows ref struct generic constraint. However, this feature required changes in the language, SDK and runtime, so it won't be available with older .NET verswions.