Consider the following C# code:
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;
}
}
The idea is to return the argument as a particular specialization of Span<T>
(in this case, Span<int>
) if the argument is actually of that type at runtime; otherwise, just return an empty span.
We can see that this approach works with an array, but fails with a span. Is there a workaround to do this with spans as well?
If you can add where T : struct
, there's a method for that:
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;
}
Otherwise, here's another way:
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;
}
It deconstructs and reconstructs the span, as you can't just use Unsafe.As
for this, since Span
is a ref
struct and therefore it's not usable as a type parameter.
The if (typeof(T) == typeof(int))
check is optimized away by the JIT.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With