Why is Nullable <> not hiding GetType?

Based on this question, why does n.GetHashCode () work, but does n.GetType () throw and throw? John's answer gave me the question: why isn’t Nullable<> hiding GetType :

 public new Type GetType() { return GetValueOrDefault().GetType(); } 

Because then it

 int? i = null; Console.WriteLine(i.GetType().Name); 

should work, right? Am I missing something? What are the caveats? I tried Google, but did not find a satisfactory explanation.

Update : specify: a little. It works:

 int? i = null; Console.WriteLine(i.GetHashCode()); 

The only reason i.GetType() throws is because GetType not virtual and cannot be overridden. Therefore, when called, i inserted into the object, the result of which is null , and then it throws. However, if Nullable will be implemented as follows

  public struct Nullable<T> where T : struct { .... public new Type GetType() { return GetValueOrDefault().GetType(); } } 

Then this would make the behavior more consistent (imho) in that it would all work, and not just the first two calls:

  int? i = null; Console.WriteLine(i.GetHashCode()); Console.WriteLine(i.ToString()); Console.WriteLine(i.GetType()); 
+4
source share
2 answers

I think because GetType returns the exact type of the current instance of time. In this case, it does not have a runtime type, because it refers to null .

Consider the following example:

  MyBaseClass myBase = null; MyDerivedClass myDerived = null; object o = myDerived; MyBaseClass b = myDerived; 

If myBase.GetType() returns MyBaseClass and myDerived.GetType() returns MyDerivedClass , then what should o.GetType() and b.GetType() return?

The reason Nullable does not just hide object.GetType and returns its compile time type when it is null , probably because it breaks the GetType contract.

+2
source

I think the reason they did not do this is usually a bad idea to hide the inherited method using the new method with the same name and signature.

If they decide to hide Object.GetType() , the question is whether they should return a structure type of Nullable<T> or a base type. It will 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" type of runtime i is definitely Nullable<int> (also known as int? ). Of course, now the new GetType method (for example, in .NET 5.0) that returned a Nullable<int> will be a change. This is because, as it is today, i will be placed in the null link or in the int box ( not in the Nullable<int> box) due to the magic box Nullable<> .

But: Is there no reason for a (capable) programmer to use .GetType() for a variable (or other expression) such as T? compilation time T? Because he knows that the actual type coincides with the type of compile-time, namely typeof(T?) . He also knows that the base type is typeof(T) .

For the same reason, for a "normal" (non-null) value of type T , it is not useful for the 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 private types. Also, for a for a reference type that is sealed (and for which the type parameter is not covariant or contravariant) .GetType() 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<> structure are System.ValueType and System.Object , and Nullable<> does not implement any interfaces. But if our i from before is cast and put into a variable of type compilation time ValueType or object (or dynamic ), it loses its Nullable<int> identity and becomes a regular boxed type. Therefore, even if Object.GetType() was made virtual (which, of course, would be extremely dangerous), this would not even help.

Conclusion: the runtime type is Nullable<> if and only if the compile time type is Nullable<> , so this "problem" is not interesting to fix.

0
source

Source: https://habr.com/ru/post/1346702/


All Articles