为什么Nullable<>不要隐藏GetType?

时间:2011-04-05 09:17:04

标签: c# .net

来自这个问题why does n.GetHashCode() work but n.GetType() throws and exception? Jon给出的答案让我想到了这个问题:为什么Nullable<>没有隐藏GetType

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

因为那时

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

应该工作,不应该吗?我错过了一些明显的东西吗有什么警告?我试过谷歌,但没有找到任何令人满意的解释。

更新:澄清一下。这有效:

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

i.GetType()抛出的唯一原因是GetType不是虚拟的,无法覆盖。所以当调用它时i被装入对象,导致null然后它抛出。但是,如果Nullable将像这样实施

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

然后它会使行为更加一致(imho),所有这些都会起作用,而不仅仅是前两个调用:

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

2 个答案:

答案 0 :(得分:2)

我认为这是因为GetType返回当前实例的确切运行时类型。在这种情况下,它没有运行时类型,因为它引用了null

考虑这个例子:

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

如果myBase.GetType()返回MyBaseClassmyDerived.GetType()将返回MyDerivedClass,那么o.GetType()b.GetType()会返回什么?

Nullable不是简单地隐藏object.GetType并且在null时返回其编译时类型的原因,可能是因为它会破坏GetType的合同。

答案 1 :(得分:0)

我认为他们没有这样做的原因是,使用具有相同名称和签名的new方法隐藏继承的方法通常是个坏主意。

如果他们选择实际隐藏Object.GetType(),问题是他们是否应该返回Nullable<T>结构的类型或基础类型。这可能是:

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

或:

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

如果你有:

int? i = null;

或:

int? i = 42;

i的“真实”运行时类型肯定是Nullable<int>(也称为int?)。当然,现在引入一个新的GetType方法(在.NET版本5.0中),返回Nullable<int>将是一个重大变化。这是因为今天的方式,i将被加入null引用或加框int 由于Nullable<int>的神奇拳击,装箱Nullable<>)。

但是:一个(有能力的)程序员真的没有理由在 编译时类型的变量(或其他表达式)上使用.GetType() T?,因为知道实际类型与编译时类型相同,即typeof(T?)。他也知道基础类型是typeof(T)

出于同样的原因,对于“通常”(不可为空)值类型T,当编译时类型为{{1}时,程序员使用.GetType()没有用处因为他知道,结果将永远是T。这是因为所有值类型都是密封类型。此外,对于密封的参考类型(并且没有类型参数是共变或逆变),typeof(T)是无用的。

举个例子:

.GetType()

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. 结构的基类是Nullable<>System.ValueType,而System.Object不实现任何接口。但是如果我们之前的Nullable<>被强制转换并放入编译时类型iValueType(或object)的变量中,则丢失它的dynamic标识,并成为普通的盒装值类型。因此,即使Nullable<int> Object.GetType() virtual(当然这将是非常危险的),它甚至都没有帮助。

结论:当且仅当编译时类型为Nullable<>时,运行时类型为Nullable<>,因此修复此“问题”并不重要。