I think the reason why they didn't do that is that it is generally a bad idea to hide an inherited method with a new
method with the same name and signature.
If they chose to actually hide Object.GetType()
, the question is if they should return the type of the Nullable<T>
struct, or the underlying type. This would be either:
public struct Nullable<T> where T : struct
{
....
public new Type GetType()
{
return typeof(Nullable<T>);
}
}
or:
public struct Nullable<T> where T : struct
{
....
public new Type GetType()
{
return typeof(T);
}
}
If you have:
int? i = null;
or:
int? i = 42;
the "real" runtime type of i
is certainly Nullable<int>
(also known as int?
). Of course, introducing a new GetType
method now (in .NET version 5.0, say) which returned Nullable<int>
would be a breaking change. That's because the way it is today, the i
will be boxed into either a null
reference or a boxed int
(not a boxed Nullable<int>
) because of the magical boxing of Nullable<>
.
But: There is really no reason for a (capable) programmer to ever use .GetType()
on a variable (or other expression) of compile-time type T?
, because he knows the actual type is the same as the compile-time type, namely typeof(T?)
. He also knows that the underlying type is typeof(T)
.
For the same reason, for a "usual" (not nullable) value type T
, it is not useful for a programmer to use .GetType()
when the compile-time type is T
, because he knows the result will always be typeof(T)
. This is because all value types are sealed types. Also, for a for a reference type which is sealed (and for which no type parameter is co- or contravariant), .GetType()
is useless.
To give an example:
string str = ...;
...
var t = str.GetType(); // This is really useless. If str is null
// an exception is thrown. Otherwise the
// t will ALWAYS be typeof(string) because
// the class System.String is a sealed class.
The base classes of the Nullable<>
struct are System.ValueType
and System.Object
, and Nullable<>
implements no interfaces. But if our i
from before is cast and put into a variable of compile-time type ValueType
or object
(or dynamic
), it loses its identity of Nullable<int>
and becomes an ordinary boxed value type. Therefore, even if Object.GetType()
were made virtual
(which would of course be extremely dangerous) it wouldn't even be helpful.
Conclusion: The runtime type is Nullable<>
if and only if the compile-time type is Nullable<>
, so this "problem" is not interesting to fix.