• 《C#高级编程(第6版)》第6章筆記第6章运算符和类型强制转换


    运算符和类型强制转换

    checked和unchecked运算符
    为此,C#提供了checked和unchecked运算符。如果把一个代码块标记为checked,CLR就会执行溢出检查,如果发生溢出,就抛出异常。

    is运算符
    is运算符可以检查对象是否与特定的类型兼容。"兼容"表示对象是该类型,或者派生于该类型。

    as运算符
    as运算符用于执行引用类型的显式类型转换。如果要转换的类型与指定的类型兼容,转换就会成功进行;如果类型不兼容,as运算符就会返回值null。

    sizeof运算符
    使用sizeof运算符可以确定堆栈中值类型需要的长度(单位是字节)

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

    可空类型和运算符
    如果在程序中使用可空类型,就必须考虑null值在与各种运算符一起使用时的影响。通常可空类型与一元或二元运算符一起使用时,如果其中一个操作数或两个操作数都是null,其结果就是null。
    null值的可能性表示,不能随意合并表达式中的可空类型和非可空类型

    空接合运算符
    空接合运算符(??)提供了一种快捷方式,可以在处理可空类型和引用类型时表示Null值。这个运算符放在两个操作数之间,第一个操作数必须是一个可空类型或引用类型,第二个操作数必须与第一个操作数的类型相同,或者可以隐含地转换为第一个操作数的类型。空接合运算符的计算如下:如果第一个操作数不是null,则整个表达式就等于第一个操作数的值。但如果第一个操作数是null,则整个表达式就等于第二个操作数的值。

    C#有两种转换方式:隐式转换方式和显式转换方式。
    注意,只能从较小的整数类型隐式地转换为较大的整数类型,不能从较大的整数类型隐式地转换为较小的整数类型。也可以在整数和浮点数之间转换,其规则略有不同,可以在相同大小的类型之间转换,例如int/uint转换为 float,long/ulong转换为double,也可以从long/ulong转换回float。这样做可能会丢失4个字节的数据,但这仅表示得到的float值比使用double得到的值精度低,编译器认为这是一种可以接受的错误,而其值的大小是不会受到影响的。无符号的变量可以转换为有符号的变量,只要无符号的变量值的大小在有符号的变量的范围之内即可。
    在隐式转换值类型时,可空类型需要额外考虑:

    ● 可空类型隐式转换为其他可空类型,应遵循表6-4中非可空类型的转换规则。即int? 隐式转换为long?、float?、double?和decimal?。

    ● 非可空类型隐式转换为可空类型也遵循表6-4中的转换规则,即int隐式转换为long?、float?、double?和decimal?。

    ● 可空类型不能隐式转换为非可空类型,此时必须进行显式转换,如下一节所述。这是因为可空类型的值可以是null,但非可空类型不能表示这个值。


    有许多场合不能隐式地转换类型,否则编译器会报告错误。下面是不能进行隐式转换的一些场合:

    ● int转换为short-- 会丢失数据

    ● int转换为uint-- 会丢失数据

    ● uint转换为int-- 会丢失数据

    ● float转换为int-- 会丢失小数点后面的所有数据

    ● 任何数字类型转换为char -- 会丢失数据

    ● decimal转换为任何数字类型-- 因为decimal 类型的内部结构不同于整数和浮点数

    ● int? 转换为int-- 可空类型的值可以是null

    装箱和拆箱

    C#的实现方式是通过一个有点魔术性的方式,即装箱(boxing)。装箱和拆箱(unboxing)可以把值类型转换为引用类型,或把引用类型转换为值类型。

    装箱用于描述把一个值类型转换为引用类型。运行库会为堆上的对象创建一个临时的引用类型"box"。
    箱用于描述相反的过程,即以前装箱的值类型转换回值类型。这里使用术语"cast",是因为这种数据类型转换是显式进行的。


    对象的相等比较
    在讨论了运算符,并简要介绍了相等运算符后,就应考虑在处理类和结构的实例时,"相等"意味着什么。理解对象相等比较的机制对编写逻辑表达式非常重要,另外,对实现运算符重载和数据类型转换也非常重要,本章的后面将讨论运算符重载。

    对象相等比较的机制对于引用类型(类的实例)的比较和值类型(基本数据类型,结构或枚举的实例)的比较来说是不同的。下面分别介绍引用类型和值类型的相等比较。


    引用类型的相等比较
    System.Object定义了3个不同的方法,来比较对象的相等性:ReferenceEquals()和Equals()的两个版本。再加上比较运算符==,实际上有4种进行相等比较的方式。

    ReferenceEquals()是一个静态方法,测试两个引用是否指向类的同一个实例,即两个引用是否包含内存中的相同地址。作为静态方法,它不能重写,所以只能使用System.Object的实现代码。如果提供的两个引用指向同一个对象实例,ReferenceEquals()总是返回true,否则就返回false。但是它认为null等于null.

    Equals()虚拟版本的System.Object实现代码也可以比较引用。但因为这个方法是虚拟的,所以可以在自己的类中重写它,按值来比较对象。特别是如果希望类的实例用作字典中的键,就需要重写这个方法,以比较值。否则,根据重写Object.GetHashCode()的方式,包含对象的字典类要么不工作,要么工作的效率非常低。在重写Equals()方法时要注意,重写的代码不会抛出异常。这是因为如果抛出异常,字典类就会出问题,一些在内部调用这个方法的.NET基类也可能出问题。

    Equals()的静态版本与其虚拟实例版本的作用相同,其区别是静态版本带有两个参数,并对它们进行相等比较。这个方法可以处理两个对象中有一个是null的情况,因此,如果一个对象可能是null,这个方法就可以抛出异常,提供额外的保护。静态重载版本首先要检查它传送的引用是否为null。如果它们都是null,就返回true(因为null与null相等)。如果只有一个引用是null,就返回false。如果两个引用都指向某个对象,它就调用Equals()的虚拟实例版本。这表示在重写Equals()的实例版本时,其效果相当于也重写了静态版本。

    比较运算符==最好将比较运算符看作是严格的值比较和严格的引用比较之间的中间选项。

    值类型的相等比较
    在进行值类型的相等比较时,采用与引用类型相同的规则:ReferenceEquals()用于比较引用,Equals()用于比较值,比较运算符可以看作是一个中间项。但最大的区别是值类型需要装箱,才能把它们转换为引用,才能对它们执行方法。另外,Microsoft已经在System.ValueType类中重载了实例方法Equals(),以便对值类型进行合适的相等测试。如果调用sA.Equals(sB),其中sA和sB是某个结构的实例,则根据sA和sB是否在其所有的字段中包含相同的值,而返回true或false。另一方面,在默认情况下,不能对自己的结构重载==运算符。在表达式中使用(sA==sB)会导致一个编译错误,除非在代码中为结构提供了==的重载版本。

    运算符重载
    在许多情况下,重载运算符允许生成可读性更高、更直观的代码,包括:

    ● 在数学领域中,几乎包括所有的数学对象:坐标、矢量、矩阵、张量和函数等。如果编写一个程序执行某些数学或物理建模,肯定会用类表示这些对象。

    ● 图形程序在计算屏幕上的位置时,也使用数学或相关的坐标对象。

    ● 表示大量金钱的类(例如,在财务程序中)。

    ● 字处理或文本分析程序也有表示语句、子句等的类,可以使用运算符把语句连接在一起(这是字符串连接的一种比较复杂的版本)。

    另外,有许多类与运算符重载并不相关。不恰当地使用运算符重载,会使使用类型的代码很难理解。

    比较运算符的重载
    C#要求成对重载比较运算符。如果重载了==,也必须重载!=,否则会产生编译错误。


    用户定义的数据类型转换

    1. 类之间的数据类型转换

    Currency示例仅涉及到与float(一种预定义的数据类型)来回转换的类。实际上任何简单数据类型的转换都是可以自定义的。定义不同结构或类之间的数据类型转换是允许的,但有两个限制:

    ● 如果某个类直接或间接继承了另一个类,就不能定义这两个类之间的数据类型转换(这些类型的类型转换已经存在)。

    ● 数据类型转换必须在源或目标数据类型的内部定义。


    2. 基类和派生类之间的数据类型转换

    要了解这些数据类型转换是如何工作的,首先看看源和目标的数据类型都是引用类型的情况。


    3.装箱和拆箱数据类型转换

    申明

    非源创博文中的内容均收集自网上,若有侵权之处,请及时联络,我会在第一时间内删除.再次说声抱歉!!!

    博文欢迎转载,但请给出原文连接。

  • 相关阅读:
    3.8 java基础总结①多线程
    RPM Database 实战详解
    关于CentOS7.2 控制面板不显示输入法,或者无法调出输入的问题。(已解决)
    mysqldump
    一些有意思的Linux命令
    和docket的第一次亲密接触
    centos7根分区扩容(亲测有效)
    相识mongodb
    开机自动获取spark用户名和服务器
    Puppet日常总结
  • 原文地址:https://www.cnblogs.com/Athrun/p/1519541.html
Copyright © 2020-2023  润新知