Currently, calling GetType on a span throws a compiler error since GetType attempts to box the span into an object (which is not possible for ref structs).
```C#
Span
Console.WriteLine(span.GetType());
```text
error CS0029: Cannot implicitly convert type 'System.Span<byte>' to 'object'
We should add a GetType method so that it returns the expected value. In this case, it would be:
System.Span`1[System.Byte]
System.ReadOnlySpan`1[System.Byte]
Implementation:
C#
public readonly ref struct Span<T>
{
public new Type GetType() => typeof(Span<T>);
}
public readonly ref struct ReadOnlySpan<T>
{
public new Type GetType() => typeof(ReadOnlySpan<T>);
}
cc @AtsushiKan, @KrzysztofCwalina, @terrajobst, @richlander, @danmosemsft
Should this be a Roslyn issue to not box it? If it devirtualized the call, you wouldn't need the new API.
Not sure how that would work. At the end of the day, GetType() needs to retrieve the MethodTable (or EEType on Project N), and that's nowhere to be found in the unboxed struct.
Ick. Good point. For some reason I had thought GetType() was virtual, but of course it isn't. This doesn't quite work if we ever add a generic constraint for Span or byref-like types (which we might need to do for other reflection support), but it doesn't hurt much to have it. The only problem I can think of is code that looks something like:
typeof(Span<int>).GetMethods().Where(m => m.Name == "GetType").Single();
You will get the same problem on any ref structs for any System.Object instance methods. Are we going to add a boiler-plate GetType() to all public ref structs?
A centralized solution would be nice but I can't think of a cheap way to do it. All my ideas lead down the path to either Roslyn or the JIT rewriting those calls into "ldtoken - call Type.GetTypeFromHandle()" I'd find it hard to justify the cost of that just to fix this problem.
What is the problem (use case) that this is fixing? Why would somebody want to call GetType on Span?
I can't think of a place where this would be needed, especially since I think the only (sensible) time the type of a ref struct could be questioned is when it's a generic. Inheritance doesn't work with structs in general and interfaces can't be implemented with ref structs so the only time it can be (sensibly) passed as a questionable type is when generics are considered. However even if the ref struct where generic and passed to some method then it'll be possible to determine T with typeof(T).
Having said this though I do think there are a couple of aspects that lead to confusion:
The issue was brought up by @richlander, where he wanted to use GetType to print out the type to show the distinction between span and array. As @tdinucci mentioned, it is difficult for me to come up with a more extensive scenario where we use GetType on span. Leaving it as api-needs-work for now to see if someone can come up with a viable use case.
I mean... not being able to use GetType is a pretty insightful distinction between span and array, too. 馃榿
This issue hasn't been touched in nearly 2 years and a viable use case hasn't yet been presented. Should we go ahead and close it?
Alternatively: as mentioned earlier, the compiler could special-case <struct>.GetType() and replace it with the IL it would have generated for an equivalent typeof(<struct>) statement. That will work for all struct types, including ref structs. If that's the desired course of action then this issue should be moved to the _csharplang_ repo.
Most helpful comment
I mean... not being able to use GetType is a pretty insightful distinction between span and array, too. 馃榿