• 运算符和强制类型转换


    本文主要介绍一下C#中的运算符和类型强制转换,主要内容包括
    1.C#中的可用运算符
    2.处理引用类型和值类型时相等的含义
    3.基本数据类型之间的数据转换
    4.装箱和开箱技术
    5.通过强制转换技术在引用类型之间转换
    6.运算符重载
    7.自定义类型强制转换
    下面详细介绍这7点内容

    一、C#中的可用运算符
    C#中的运算符跟c语言中的差不多,这里介绍几个特殊的运算符
    1.1 check和uncheck运算符
          如果把一个代码块标记为checked,CLR就会执行溢出检查,如果发生溢出,就抛出异常。如果要禁止溢出检查,可以把代码标记为unchecked。unchecked是默认值。
    //运行下面这段代码,就会抛出异常
    byte b=255;
    checked
    {
      b
    ++;
    }

    Console.WriteLine(b.ToString());

    //运行下面这段代码,则不会抛出异常
    byte b=255;
    unchecked
    {
      b
    ++;
    }

    Console.WriteLine(b.ToString());

    1.2 is运算符
    is运算符可以检查对象是否与特定的类型兼容。
    int i = 10;
    if(i is object)
    {
      Console.WriteLine(
    "i is an object");
    }

    1.3 as运算符
    as运算符用于执行引用类型的显示类型转换。如果转换类型与指定的类型兼容,转换成功;如果不兼容,返回null
    object o1 = "some string";
    object o2 = 5;
    string s1 = o1 as string;  //s1="some string"
    string s2 = o2 as string;  //s2=null 

    1.4 sizeof运算符
    使用sizeof运算符可以确定堆栈中值类型需要的长度(单位字节):注意只能在不安全的代码中使用sizeof
    例如:sizeof(int)

    1.5 type运算符
    返回一个表示特定类型的Type对象。
    例如:typeof(string)返回表示System.String类型的Type对象。在使用反射动态查找对象信息时,这个运算很有效。

    二、类型转换

    2.1 隐式转换
    只能从较小的整数类型隐式转换为较大的整数类型,不能从较大的整数类型隐式地转换为较小地整数类型。
    无符号的变量可以转换为有符号的变量,只要无符号的变量值的大小在有符号的变量的范围之内即可。
    例如:
    byte v1 = 10;
    byte v2 = 23;
    long total;
    total 
    = v1 + v2;//v1、v2均隐式转换为long类型

    2.2显示转换
    在不能隐式转换的时候,可以显示执行这些转换。格式如下:
    long val = 3000000000;
    int i = (int)val;//编译不会报错
    所有的显示数据类型转换都可能不安全,在应用程序中应包含处理可能失败的数据类型转换的代码。例如:try/catch等
    显示转换有一些限制,值类型只能在数字、char类型和enum类型之间转换。不能直接把Boolean数据类型转换为其他类型,也不能把其他类型转换为Boolean数据类型。

    2.3装箱和取消装箱
    装箱可以把值类型转换成引用类型(boxing),取消装箱可以把引用类型转换成值类型(unboxing)
    int i = 20;

    object o = i;  //boxing

    int j = (int)o; //unboxing

    三、对象的相等比较

    3.1 引用类型的相等比较
    有四种方法:
    1)ReferenceEquals()方法
          ReferenceEquals()方法是一个静态方法,不能重写,只能使用System.object实现。如果提供的两个引用指向同一个对象实例,ReferenceEquals()方法
    返回true,否则返回false。但是该方法认为null等于null。
    SomeClass x,y;
    = new SomeClass();
    = new SomeClass();
    bool B1 = ReferenceEquals(null,null);// return true;
    bool B2 = ReferenceEquals(null,x);// return false;
    bool B3 = ReferenceEquals(x,y);// return false because x and y point to different objects;

    2)虚拟的Equals()方法
          Equals()方法是虚拟的,所以可以在自己的类中重写。
    3)静态的Equals()方法
          静态的Equals()方法和虚拟的Equals()方法作用相同,区别是静态版本带有两个参数。静态方法可以处理两个对象中有一个是null的情况。
    4)比较运算符==
          ==可以看作是严格值比较和严格引用比较之间的中间选项,使用时最好重写==运算符

    3.2 值类型的相等比较
          值类型的相等比较与引用类型的相等比较采用相同的规则,最大的区别就是值类型需要装箱,才能执行上面介绍的四种方法。

    四、运算符重载

     4.1 算术运算符重载    例如:
    //定义结构Vector
    struct Vector
    {
      
    public double x,y,z;
      
    public Vector(double x,double y,double z)
      
    {
        
    this.x = x;
        
    this.y = y;
        
    this.z = z;
      }

      
    public Vector(Vector rhs)
      
    {
        
    this.x = rhs.x;
        
    this.y = rhs.y;
        
    this.z = rhs.z;
      }

      
    public override string ToString()
      
    {
        
    return "(" + x + "," + y + "," + z + ")";
      }

      
    //重载+运算符
      public static Vector operator + (Vector lhs, Vector rhs)//C#要求所有的运算符重载都声明为public和static
      {
        Vector result 
    = new Vector(lhs);
        result.x 
    += rhs.x;
        result.y 
    += rhs.y;
        result.z 
    += rhs.z;
        
    return result;
      }

    }


    //测试
    static Main()
    {
      Vector vect1,vect2,vect3;
      vect1 
    = new Vector(3.0,3.0,1.0);
      vect2 
    = new Vector(2.0,-4.0,-4.0);
      vect3 
    = vect1 + vect2;
      Console.WriteLine(
    "vect1=" + vect1.ToString());
      Console.WriteLine(
    "vect2=" + vect2.ToString());
      Console.WriteLine(
    "vect3=" + vect3.ToString());
    }


    //编译运行,结果如下:
    vect1=(3,3,1)
    vect2
    =(2,-4,-4)
    vect3
    =(5,-1,-3)
    注意:C#不允许重载=运算符,但如果重载+运算符,编译器就会自动使用+运算符的重载来执行+=运算符的操作。-=、&=、*=、/=也遵循此规则

    4.2 比较运算符重载
    1)C#要求成对重载比较运算符(==和!=、>和<、>=和<=共3对),如果不成对重载,编译就会出错。
    2)必须返回bool类型的值。
    注意:重载==和!=时,还应重载System.object的Equals()方法和GetHashCode()方法,否则产生一个编译警告。因为Equals()方法执行与==相同的相等逻辑。
    除此之外,比较运算符重载跟算术运算符的重载没有区别。

    五、用户定义的数据类型转换

    用户定义的数据类型转换和预定义的数据类型转换一样,也分隐式转换和显示转换两种。
    如果知道无论在源变量中存储什么值,数据类型转换总是安全的,就可以用隐式转换;
    如果某些数据值可能会出错,就应该把数据类型转换定义为显示的。
    定义数据类型的转换类似于运算符重载:
    public static implicit operator float(Currency value)
    {
      
    //processing
    }
    执行用户类型转换的完整示例:
    struct Currency
    {
      
    public uint Dollars;
      
    public ushort Cents;
      
    public Currency(uint dollars, ushort cents)
      
    {
        
    this.Dollars = dollars;
        
    this.Cents = cents;
      }

      
    public override string ToString()
      
    {
        
    return string.Format("${0}.{1,-2.00}",Dollars,Cents);
      }

      
    //隐式转换
      public static operator float(Currency value)
      
    {
        
    return value.Dollars + (value.Cents/100.0f
    );
      
    //显示转换
      public static operator Currency(float value)
      
    {
        
    uint dollars = (uint)value;
        
    ushort cents = (ushort)((value-dollars)*100);
        
    return new Currency(dollars,cents);
      }

      }

    }


    //测试
    static Main()
    {
      Currency balance 
    = new Currency(50,35);
      Console.WriteLine(balance);
      Console.WriteLine(
    "balance is " + balance);
      Console.WriteLine(
    "balance is (using ToString())" + balance.ToString());
      
    float balance2 = balance;
      Console.WriteLine(
    "After converting to float," + balance2);
      balance 
    = (Currency)balance2;
      Console.WriteLine(
    "After converting back to currency," + balance);
    }


    //结果
    50.35
    balance 
    is $50.35
    balance 
    is (using ToString()) $50.35
    After converting to 
    float,50.35
    After converting back to currency,$
    50.34" 

    5.1 类之间的数据类型转换
         两个限制:
         1)如果某个类直接或间接继承了另一个类,就不能在这两个类之间进行数据类型转换。
         2)数据类型转换必须在源或者目标数据类型定义的内部定义。

    5.2 基类和派生类之间的数据转换       
    //类MyDerived派生于类MyBase
      MyDerived derivedObject = new MyDerived();
      MyBase baseCopy 
    = derivedObject;//隐式转换

      MyBase baseObject 
    = new MyBase();
      MyDerived derivedCopy 
    = (Myderived)baseObject;//抛出异常

    5.3 装箱和取消装箱数据类型转换
          值类型到object的转换是隐式转换 ,即装箱     
    Curency banlance = new Currency(40,10);
    object baseCopy = banlance;//隐式转换
         object到值类型的转换是显示转换,即取消装箱
    object derivedObject = new Currency(40,10);
    object baseObject = new object();
    Currency derivedCopy1 
    = (Currency)derivedObject;//OK
    Currency derivedCopy2 = (Currency)baseObject;//抛出异常

    5.4 多重数据类型转换
         
    Currency balance = new Currency(40,10);
    long amount = (long)balance;//Currency->float->long
    double amountD = balance;//Currency->float->double
  • 相关阅读:
    《编程珠玑番外篇-O 中间语言和虚拟机漫谈》
    《编译原理之美》笔记——后端部分
    《编译原理之美》笔记——前端部分
    《从语言编译器源码入手,编译原理该这么学》
    知识图谱简介
    支持向量机原理讲解(一)
    一个完整的机器学习项目在Python中演练(四)
    多GPU使用详解
    数据可视化
    详解谱聚类原理
  • 原文地址:https://www.cnblogs.com/ronli/p/2086446.html
Copyright © 2020-2023  润新知