考虑以下 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 优化掉。关于c# - 将泛型 Span<T> 转换为特定实例化(例如 Span<int>),如果它在运行时实际上属于该类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59097107/