什么时候可以为空的类型抛出异常?

Кир*_*рин 29 .net c# nullable nullreferenceexception

请考虑以下代码:

int? x = null;
Console.Write ("Hashcode: ");
Console.WriteLine(x.GetHashCode());
Console.Write("Type: ");
Console.WriteLine(x.GetType());
Run Code Online (Sandbox Code Playgroud)

执行时,它会写入Hashcode 0,但NullReferenceException在尝试确定类型时失败x.我知道调用可空类型的方法实际上是在底层值上调用的,所以我希望程序在期间失败x.GetHashCode().

那么,这两种方法之间的根本区别是什么,为什么第一种方法失败呢?

Che*_*hen 34

这是因为int? x = null;基本上创建了一个值类型的实例System.Nullable<int>,带有"内部" null值(您可以通过.HasVaueProperty 检查它).当GetHashCode调用时,覆盖Nullable<int>.GetHashCode是候选方法(因为该方法是虚拟的),现在我们有一个实例Nullable<int>,并执行其实例方法,完美.

调用时GetType,该方法是非虚拟的,所以的实例Nullable<int>是盒装到System.Object第一,根据该文件,和盒装值null,因此NullReferenceException.


Eri*_*ert 16

澄清Danny Chen的正确答案:

  • Nullable<T>是一种值类型.值类型包含bool,表示nullity(false表示null),T表示值.
  • 与所有其他值类型不同,可空类型不会装箱到盒装Nullable<T>.它们可以装入盒装T或空引用.
  • 由值类型S实现的方法被实现为好像它具有不可见的ref S参数; 那就是如何this通过.
  • 由引用类型C实现的方法被实现为好像存在不可见的C参数; 那就是如何this通过.
  • 有趣的情况是在引用基类中定义的虚方法,并由从基类继承的结构覆盖.

现在你有足够的信息来推断会发生什么.GetHashCode是虚拟的并被覆盖,Nullable<T>所以当你调用它时,你称之为有一个不可见的ref Nullable<T>参数this.没有拳击发生.

GetType不是虚拟的,因此无法覆盖并定义object.因此它期望一个objectfor this,当Nullable<T>在接收器上调用时必须装箱,因此可以将box设置为null,因此可以抛出.

如果你打电话,((object)x).GetHashCode()那么你会看到一个例外.

  • @Nisarg:就在你有`C类{void M(int x){...}}`并且你有`C c = new C(); cM(123);`然后以某种方式`c`必须在`M`中成为`this`.发生的方式是,逻辑上调用就像你有`class C {static void M(C _this,int x){...}}`和调用`CM(c,123)`一样.`this`在逻辑上只是另一个参数*.类似于结构,除了结构`this`是变量的`ref`别名. (3认同)

Sun*_*nil 5

执行情况Nullable<T>.GetHashCode()如下:

public override int GetHashCode()
{
    if (!this.HasValue)
    {
        return 0;
    }
    return this.value.GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)

因此,当值为null时,它将始终为您提供0.

x.GetType()null.GetType()抛出相同Object reference not set to an instance of an object