将通用 Span<T> 转换为特定实例化(例如 Span<int>),如果它在运行时实际上是该类型,则



请考虑以下 C# 代码:

using System;
public static class C
{
public static int[] TryGetIntArray<T>(T[] x)
{
if (x is int[] arr) // ok
return arr;
return Array.Empty<int>();
}
public static Span<int> TryGetIntSpan<T>(Span<T> x)
{
if (x is Span<int> span) // An expression of type 'Span<T>' cannot be handled by a pattern of type 'Span<int>'.
return span;
return Span<int>.Empty;
}
}

这个想法是将参数作为Span<T>的特定专用化返回(在本例中为Span<int>(,如果参数在运行时实际上是该类型;否则,只需返回一个空范围。 我们可以看到这种方法适用于数组,但不适用于跨度。有没有解决方法也可以对跨度执行此操作?

如果你可以添加where T : struct,有一个方法可以做到这一点:

public static Span<int> TryGetIntSpan<T>(Span<T> x)
where T : struct
{
if (typeof(T) == typeof(int))
return MemoryMarshal.Cast<T, int>(x);
return Span<int>.Empty;
}

否则,这是另一种方法:

public static Span<int> TryGetIntSpan<T>(Span<T> x)
{
if (typeof(T) == typeof(int))
return MemoryMarshal.CreateSpan(ref Unsafe.As<T, int>(ref MemoryMarshal.GetReference(x)), x.Length);
return Span<int>.Empty;
}

它解构并重建跨度,因为您不能只为此使用Unsafe.As,因为Span是一个ref结构,因此它不能用作类型参数。

if (typeof(T) == typeof(int))检查由 JIT 优化。

最新更新