zoukankan      html  css  js  c++  java
  • 谈谈值类型与null的判等比较!

    如果一个值类型没有重载==运算符,是无法直接使用==来进行值类型的实例和null的判等比较的,这个是显而易见的,默认情况下值类型都没有重载==运算符:

    A a;

    if(a==null)     //

    struct A

    {

         public int x;

    }

    但是,是否重载了==就可以把值类型的实例和null做判等比较了呢?现在,我们来看一个更加能说明问题的Demo:

    using System;

    namespace StructOperatorDemo
    {
    class Program
    {
    public struct MyStruct1
    {
    public Guid UniqueId;
    public MyStruct1(Guid fUniqueId)
    {
    this.UniqueId = fUniqueId;
    }
    }

    public struct MyStruct2
    {
    public int Value;
    public MyStruct2(int fValue)
    {
    this.Value = fValue;
    }

    public static bool operator !=(MyStruct2 s1, MyStruct2 s2)
    {
    return s1.Value != s2.Value;
    }
    public static bool operator ==(MyStruct2 s1, MyStruct2 s2)
    {
    return s1.Value == s2.Value;
    }

    public override int GetHashCode()
    {
    return this.Value;
    }
    }

    static void Main(string[] args)
    {
    // 错误: 运算符“==”无法应用于 “MyStruct1” 和 “<null>” 类型
    // MyStruct1 myStruct1 = new MyStruct1();
    // if (myStruct1 == null)
    // {

    // }

    // 正确
    MyStruct2 myStruct2;
    if (myStruct2 == null)
    {
    Console.WriteLine("myStruct2==null");
    }
    }
    }
    }
         这里重载了==运算符就使得myStuct2==null通过了编译,情况似乎有些诡异,因为貌似==两边的类型无法匹配重载的定义!
    首先,我们尝试在==运算符重载方法中加断点,结果观察到里面的代码并没有执行。
    自从.NET Framework2.0引入了可空类型,只要你定义了==运算符重载(两个参数类型必须都是原类型才可以),这里C#编译器会认可这个判等表达式,由于 一个值类型的实例永远不可能等于可空类型的null,所以这里C#编译器智能的认为这个判等表达式永远为false,我们来看看Main方法的IL
    .method private hidebysig static void  Main(string[] args) cil managed
    {
      .entrypoint
      // 代码大小       9 (0x9)
      .maxstack  2
      .locals init ([0] valuetype ConsoleApplication1.MyStruct2 myStruct2,
               [1] bool CS$4$0000)
      IL_0000:  nop
      IL_0001:  ldc.i4.0
      IL_0002:  ldc.i4.0
      IL_0003:  ceq         //这里比较的是0和0,这个行为很有趣,==结果是固定的情况下就比较0和0,!=结果固定的情况下比较的是0和1
      IL_0005:  stloc.1    //比较结果放入临时变量CS$4$0000中,但是以后根本就不使用了!
      IL_0006:  br.s       IL_0008    //无条件跳转,if里的代码并没有生成IL
      IL_0008:  ret
    } // end of method Program::Main
    这里值类型和null的判等比较只有当重载==运算符,并且两个参数类型必须都是原类型才可以,比如我们这样修改重载方法:
                public static bool operator ==(MyStruct2 s1, MyStruct1 s2) //修改第二个参数类型
    {
    return s1.Value == s2.GetHashCode();
    }
    这样会出现编译错误了:运算符“==”无法应用于 “MyStruct1” 和 “<null>” 类型
    实际上由于值类型和null的比较结果是一定的,所以也没有必要做判等比较,这里只是观察一下C#编译器的一些行为,希望把一些有趣的现象分享给大家!

    希望大家多多指教啊!


     
  • 相关阅读:
    git打补丁、还原补丁
    mysql 查两个表相同的值
    系统更新后vs2012无法打开方案资源管理器
    Node.js之Buffer
    html元素固定
    在windows上用netsh动态配置端口转发
    Git忽略规则及.gitignore规则不生效的解决办法
    MySQL5.7.10 初始化失败error
    Nginx和PHP-FPM的启动、重启、停止脚本分享
    centos添加nginx为系统服务
  • 原文地址:https://www.cnblogs.com/xuefeng1982/p/1602358.html
Copyright © 2011-2022 走看看