为什么 ReadOnlySpan 不能用作泛型委托和泛型方法的类型参数?

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

我理解为什么 ReadOnlySpan 不能用作泛型 类 的类型参数。 ReadOnlySpan 只是堆栈,因此它不能用作字段类型,字段成员像它的容器对象一样存在于堆中。但是 return 值和参数始终只是堆栈,那么为什么 ReadOnlySpan 不能用作泛型委托和泛型方法的类型参数?

这里有一个例子可以说明我在说什么:

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);
        }

    }
}

非常不幸,因为它迫使我有两个相同版本的 DoSomething 方法,使我的代码非常 WET。

注意:对于面向 .NET Framework 的项目,您需要安装 System.Memory Nuget 包。

Adam Sitnik 的 post

Let’s consider following C# code:

Span<byte> Allocate() => new Span<byte>(new byte[256]);

void CallAndPrint<T>(Func<T> valueProvider) // no generic requirements for T
{
    object value = valueProvider.Invoke(); // boxing!

    Console.WriteLine(value.ToString());
}

void Demo()
{
    Func<Span<byte>> spanProvider = Allocate;
    CallAndPrint<Span<byte>>(spanProvider);
}

As you can see the non-boxing requirement can not be ensured today if we allow the Span to be generic type argument. One of the possible solutions could be to introduce new generic constraint: stackonly. But then all the managed compilers would have to respect it and ensure the lack of boxing and other restrictions. This is why it was decided to simply forbid using Span as a generic argument.