c# - C# 中使用 ReadOnlySpan 进行泛型类型推断

标签 c# .net-core type-inference

我正在尝试创建一种在通用 ReadOnlySpan<T> 上运行的方法,这样我就可以传递数组或堆栈分配的缓冲区,而无需更改代码。我还想限制类型 T仅作为值类型。

该方法如下所示:

void Test1<T>(ReadOnlySpan<T> foo) where T : struct
{
}

但是,编译器无法在不传递类型参数的情况下推断类型:

Test1(new[] {42}); // Doesn't compile
Test1<int>(new[] {42}); // Compiles

我还尝试了不同的方法,发现了一些有趣的行为:

void Test1<T>(ReadOnlySpan<T> foo) where T : struct
{
}

void Test2<T>(T[] foo) where T : struct
{
}

void Test3<T>(T[] foo)
{
}

void Test4<T>(ReadOnlySpan<T> foo)
{
}

void Test5<T>(List<T> foo) where T : struct
{
}

void Test6<T>(List<T> foo)
{
}

Test1(new[] {42}); // NO
Test2(new[] {42}); // OK
Test3(new[] {42}); // OK
Test4(new[] {42}); // NO
Test5(new List<int> {42}); // OK
Test6(new List<int> {42}); // OK

Test1<int>(new[] {42}); // OK
Test4<int>(new[] {42}); // OK

似乎类型推断仅适用于 *Span 。 s(数组和 List 工作正常),我猜想 ReadOnlySpan 的事实是ref struct可能是问题的原因。

造成这种不同行为的真正原因是什么?

有没有办法帮助编译器推断 ReadOnlySpan 的数据类型在Test1()方法?

更新:

我尝试显式声明参数的类型:

ReadOnlySpan<int> testSpan = new[] {42};
Test1(testSpan); // OK!

Span<int> test = new[] {42};
Test1(test); // NO

看来这里真正的问题是隐式转换。

有谁能解释一下吗?

最佳答案

让我们关注type inference process !

在第一阶段,此案例匹配:

if Eᵢ has a type U and the corresponding parameter is a value parameter (§15.6.2.2) then a lower-bound inference is made from U to Tᵢ.

将其应用于本例,即“new[] {42} 具有类型 int[] ,然后从 int[]ReadOnlySpan<T> 进行下限推断”。

指定如何进行下限推理 here .

A lower-bound inference from a type U to a type V is made as follows:

这里Uint[]VReadOnlySpan<T> ,而这一步正是出错的地方。浏览案例,ReadOnlySpan<T>不是T ,它也不能为空,所以我们要做的是:

Otherwise, sets U₁...Uₑ and V₁...Vₑ are determined by checking if any of the following cases apply:

在这里它找到“相关的”泛型类型参数和数组组件类型,并对它们进行推断。例如,它可以用简单的语言做出以下推论:

given a List<Foo> argument, and a IEnumerable<T> parameter, then T must be Foo or some superclass of it (aka a "lower bound").

在上述情况下,U₁...Uₑ 将为 Foo ,而 V₁...Vₑ 将为 T .

不幸的是,这些情况都不适用于 int[]ReadOnlySpan<T> ,所以不做任何推断。

这些情况处理数组类型(例如 int[]T[] ),

V is an array type V₁[...]and U is an array type U₁[...] of the same rank

从数组类型到集合接口(interface)的隐式转换(例如 int[]IEnumerable<T> ),

V is one of IEnumerable<V₁>, ICollection<V₁>, IReadOnlyList<V₁>, IReadOnlyCollection<V₁> or IList<V₁> and U is a single-dimensional array type U₁[]

以及相互继承/实现的泛型类型的类型参数(例如 Dictionary<string, int>IDictionary<T, U> )。

V is a constructed class, struct, interface or delegate type C<V₁...Vₑ> and there is a unique type C<U₁...Uₑ> such that U (or, if U is a type parameter, its effective base class or any member of its effective interface set) is identical to, inherits from (directly or indirectly), or implements (directly or indirectly) C<U₁...Uₑ>.

它不会检查任何任意隐式转换,例如从数组到 ReadOnlySpan<T> 的转换。然而。

也就是说,该语言可以被设计为在上面的第二种情况中添加一个特殊情况。添加ReadOnlySpan<T>/Span<T>到接口(interface)列表,除了IEnumerable<T>和别的。我们希望这在未来能够实现。

关于c# - C# 中使用 ReadOnlySpan 进行泛型类型推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77577043/

相关文章:

c# - Application.ExecutablePath 是否会根据测试运行程序返回不同的值?

c# - Postman 错误 : "Unable to verify the first certificate" when try to get from my .net core api

typescript - 如何使幻像类型与 TypeScript 中的方法一起使用?

haskell - 什么是单态性限制?

c# - 一个 ASP.Net ImageButton 在 Chrome 中不工作(但另一个是......并且都在 IE 9 中工作)

c# - 命名管道创建时所有实例都忙异常

c# - 当 access_token 长度超过约 2000 个字符时,SignalR 在连接时返回 404 -

.net - 当每 4 分钟发送一次保持事件请求时,消耗计划中的 Azure 函数仍为 “Cold Start”

flutter - 我可以向下转换一个类,使它丢失原始的构造函数吗?

c# - 从 Web Api 2 IAuthenticationFilter AuthenticateAsync 方法设置 cookie