请考虑以下 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 优化。