可空类型为什么可以为空?也许会被面试到哦。。。

  也许某天你来某一家公司面试,或许就会被问到这个问题,当你看到这个问题,也许会立即反编译下源代码看个究竟。

[Serializable, StructLayout(LayoutKind.Sequential), __DynamicallyInvokable]
public struct Nullable<T> where T: struct
{
    private bool hasValue;
    internal T value;
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable]
    public Nullable(T value)
    {
        this.value = value;
        this.hasValue = true;
    }

    [__DynamicallyInvokable]
    public bool HasValue
    {
        [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
        get
        {
            return this.hasValue;
        }
    }
    [__DynamicallyInvokable]
    public T Value
    {
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable]
        get
        {
            if (!this.HasValue)
            {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue);
            }
            return this.value;
        }
    }
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable]
    public T GetValueOrDefault()
    {
        return this.value;
    }

    [__DynamicallyInvokable]
    public T GetValueOrDefault(T defaultValue)
    {
        if (!this.HasValue)
        {
            return defaultValue;
        }
        return this.value;
    }

    [__DynamicallyInvokable]
    public override bool Equals(object other)
    {
        if (!this.HasValue)
        {
            return (other == null);
        }
        if (other == null)
        {
            return false;
        }
        return this.value.Equals(other);
    }

    [__DynamicallyInvokable]
    public override int GetHashCode()
    {
        if (!this.HasValue)
        {
            return 0;
        }
        return this.value.GetHashCode();
    }

    [__DynamicallyInvokable]
    public override string ToString()
    {
        if (!this.HasValue)
        {
            return "";
        }
        return this.value.ToString();
    }

    [__DynamicallyInvokable]
    public static implicit operator T?(T value)
    {
        return new T?(value);
    }

    [__DynamicallyInvokable]
    public static explicit operator T(T? value)
    {
        return value.Value;
    }
}

Collapse Methods

当你reflector之后,你可能会快速的认为这个就是答案,但是你真的把这个代码拷贝到编辑器中,你会发现如下的错误。

 

从图中可以看到,原来事情没有这么简单,最后还是回到了原来的问题上,null不能给值类型赋值,这个时候,你可能就比较好奇。

我们的FCL中定义的类怎么就能逃过编译器呢?

 

①:我们用ILdasm看下il代码。

class Program
    {
        static void Main(string[] args)
        {
            Nullable<Int32> i = null;
        }
    }

 

②:下面我们再将Nullable<Int32> i = null 改成 Nullable<Int32> i = 0,看看il代码是怎么样的。

class Program
    {
        static void Main(string[] args)
        {
            Nullable<Int32> i = 0;
        }
    }

 

下面我们比较比较这两张图不一样的地方。

《1》 当 Nullable<Int32> i = 0 的时候,发现Nullable被实例化了(instance),并且还调用了其构造函数(ctor(!0)),

这种情况我们看Nullable的结构体定义,发现是非常合乎情理的。

 

《2》当 Nullable<Int32> i = null 的时候,从IL代码上看,只是调用了initobj指令,并没有实例化,也没有调用构造函数,

再看看这个指令的意思:将位于指定地址的对象的所有字段初始化为空引用或适当的基元类型的 0。

①:既然是”初始化“操作,那我应该也可以写成这样:

class Program
    {
        static void Main(string[] args)
        {
            Nullable<Int32> i = new Nullable<Int32>();
        }
    }

 

②:既然是“初始化”,那么作为null的Nullable应该可以调用实例方法并不报错,这就如指令说的一样,如果成功,那就

说明null只是Nullable的一种状态,不能跟“类”中的空引用混淆。

     从上面的三张图上可以看出,也许答案就在这个里面,编译器和CLR作为“特等公民”在底层做了很多我们看不到的东西,

这其中就像上图一样给我们多加了一种”可空状态“,只是如何做的,我们看不到而已。

 

《3》既然说到null,我也很好奇的看看到底“类”下面的null是什么情况。

class Program
    {
        static void Main(string[] args)
        {
            Program p = null;
        }
    }

 

ldnull的意思是:将空引用推送到计算堆栈上。

可以看到,既然没有new,也就不会在堆中分配内存,而这里是将null放入到线程栈中,不知道编译器在initobj中

是否也有类似的操作。。。

 

最后要说的是:希望大家讨论讨论,毕竟我也是猜测而已,并没有实实在在的看到那些给我们隐藏的东西。

时间: 2025-01-26 18:34:18

可空类型为什么可以为空?也许会被面试到哦。。。的相关文章

VS2005中使用C#的新特性:可空类型

随着C#语言最新标准的出炉,现在它也提供了对可空类型的支持.这个小变化将会在处理那些包括可选项的数据库记录时非常有用.当然在其他地方,它也是非常有用的. 简单说来,可空数据类型就是包含了所定义的数据类型或者值的空(null)的类型.C#的ECMA-334标准提供了对所有C#值类型的可空版本的描述. 定义可空类型 定义可空类型和非可空类型基本类似,不同的是采用了?来表示.如定义一个整型,你可以使用简单的语句: int myInt = 1; 为了使得myInt能够存储一个空值,你可以这样声明它: i

Guava-Optional可空类型

接上篇Guava之Joiner和Splitter,本篇将介绍Guava的另外一个有用的对象Optional,这在Java中Google Guava首先给我们提出可空对象模型的.在其他语言如c#这是已经存在很久的模式,并包含在.net类库中Nullable(Int?也是一个可空类型). Null sucks 回到本文主题Optional.在我日常编程中NullPointerException是肯定是大家遇见最多的异常错误: 为此Doug Lea曾说过: Null sucks. Sir C. A.

C#基础语法:可空类型详解

  这篇文章主要介绍了C#基础语法:可空类型详解,本文分析了可空类型的源码.研究了可空类型强制转换为常规类型.可空类型的运算等内容,需要的朋友可以参考下 以下是System.Nullable在FCL中的定义. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

c#可空类型作用

可空类型用途主要是从数据库读取数据有可能为空,而不是插入使用,插入数据都要进行验证,如果要插入数据库的null,则使用DBNull.value 判断取出的数据是否为数据库中的null,如果是则赋值给可空的datetime类型的Lockdatatime 属性 tseat.Lockdatatime = reader.IsDBNull(5) ? null : (DateTime?)reader.GetDateTime(5); 判断取出的数据是否为数据库中的null,如果是则赋值给可空的int类型的Te

Java 8中的Optional 类型与 Kotlin 中的可空类型

Java 8中的Optional 类型与 Kotlin 中的可空类型 在 Java 8中,我们可以使用 Optional 类型来表达可空的类型. package com.easy.kotlin; import java.util.Optional; import static java.lang.System.out; /** * Optional.ofNullable - 允许传递为 null 参数 * Optional.of - 如果传递的参数是 null,抛出异常 NullPointerE

怎么判断值类型的变量为空啊

问题描述 怎么判断值类型的变量为空啊!! 解决方案 解决方案二:值类型不可能为空...所以不用判断....NET2.0以上如果需要可以用可空值类型...解决方案三:那怎么用啊!!解决方案四:null解决方案五:直接申明为null啊解决方案六:可空类型是System.Nullable结构的实例.可空类型可以表示其基础值类型正常范围内的值,再加上一个null值.int?num=null;if(num.HasValue==true){System.Console.WriteLine("num=&quo

C#基础知识 全面解析可空类型_C#教程

引言: C# 2.0 中还引入了可空类型,可空类型也是值类型,只是可空类型是包括null的值类型的,下面就介绍下C#2.0中对可空类型的支持具体有哪些内容(最近一直都在思考如何来分享这篇文章的,因为刚开始觉得可空类型使用过程中比较简单,觉得没有讲的必要,但是考虑到这个系列的完整性,决定还是唠叨下吧,希望对一些不熟悉的人有帮助). 一.为什么会有可空类型   如果朋友们看了我之前的分享,对于这一部分都不会陌生,因为我一般介绍C#特性经常会以这样的方式开头的, 因为每个特性都是有它出现的原因的(有一

C#难点逐个击破(8):可空类型System.Nullable_C#教程

null与void null值用来表示数据类型未被赋予任何值,它是一种引用类型:void表示没有类型,或者说是没有任何值.null与void的区别可以认为void是根本没有,而null是一个空箱子,里面什么都没有. null值只能赋值给引用类型,这里注意到string也是一种引用类型:引用类型在C中称为"指针",即存放变量位置的内存空间位置.将变量设为null,会显式地设置引用,且它本身不指向任何内存位置: null值赋给值类型将导致编译错误. void用于方法值的返回,其本质并不是一

csocket-CSocket发送空包还是接送了空包? 怎么办?!?!

问题描述 CSocket发送空包还是接送了空包? 怎么办?!?! 在MFC里定义了CSocket AfxSocketInit(); CSocket aSocket; CString strIP="127.0.0.1"; int nPort = 6000; if(!aSocket.Create()) { MessageBox("error"); return; } if(aSocket.Connect(strIP, nPort)) { char recvBuf[20]