Search code examples
c#.net.net-coreclrcil

C# Checking if object is Span<T>


Currently I am writing C# code under .NET Core 3.1 for checking if the current type (I use Mono.Cecil, but System.Reflection might suit better) is a Span type. Having found info about how to check if the type is generic, I wrote some dummy code for such sort of check:

        unsafe
        {
            IntPtr unmanagedHandle = Marshal.AllocHGlobal(16);
            Span<byte> unmanaged = new Span<byte>(unmanagedHandle.ToPointer(), 16);
            if (unmanaged is object)
                if ((unmanaged as object).GetType().GetGenericTypeDefinition() == typeof(Span<>))
                    Console.WriteLine("Span!");
            Marshal.FreeHGlobal(unmanagedHandle);
        }

Despite the official MSDN docs say that Span<> IS an object, when compiling, I get stuck with a warning and an error: CS0184 warns that "unmanaged" is never of the "object" type, and CS0039 tells that "System.Span<byte>" cannot be converted to "object" via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion. At leasts, the docs point out that Span<> is not a usual object really.

Is there any other way (having only one dependency Mono.Cecil) to determine whether some object (or another underlying piece of data, referred to by the IntPtr, at least) is a Span-derived?


Solution

  • Well, I know it is not actually fine, but I have to deal with the name checking approach. Due to the semi-object (whatever) nature of the System.Span<T> class, we cannot compare Span to any object, but we can use comparation like typeof(System.Span<byte>). This can only be useful if we always do know preliminary, how (i.e., with which T) Span can be instantiated, but this is NOT my case actually. There seem to be no reliable mechanisms to distinguish Span, besides name checking. So that, checking the type name seems to be the only suitable approach.

    Using Mono.Cecil, I used for a TypeReference the following condition:

    bool IsSpanType(TypeReference type) {
        return type.FullName.StartsWith("System.Span`1");
    }
    

    As you see, there is no happy-end, but it works fine enough though. And I cannot see any reasons to perform any more paranoid checks (like checking such properties of TypeReference like Scope, ElementType, or whatever else).