C#支持的运算符

https://msdn.microsoft.com/zh-cn/library/6a71f45d(v=vs.140).aspx

checked 和 unchecked

  1. byte b = ;
  2. b++;
  3. Console.WriteLine(b);

byte数据类型 范围 0~255。递增 b 的值会导致溢出。CLR如何处理这个溢出取决于很多因素,包括编译器选项。

可以使用代码块标记 checked,发生溢出,抛出 OverflowException 异常。

  1. byte b = ;
  2. checked
  3. {
  4. b++;
  5. }
  6. Console.WriteLine(b);

也可以用  /checked  编译器选项进行编译,就可以检查程序中所有未标记代码中的溢出。

反之 unchecked 不检查溢出,注意 unchecked 是默认行为。

  1. byte b = ;
  2. unchecked
  3. {
  4. b++;
  5. }
  6. Console.WriteLine(b);

is运算符

检查对象是否是该该类型,或者派生自该类型。

  1. int value = ;
  2. Console.WriteLine( (value is int) + " " + (value is object));

as 运算符

执行引用类型的显示类型转换。如果类型不兼容,返回null。

  1. object str = "Hello";
  2. object value = ;
  3. string str1 = str as string;
  4. string value2 = value as string;

value2 等于 null

sizeof运算符

确定在栈中值类型需要的字节大小。

  1. Console.WriteLine( sizeof(int) );

如果是复杂类型(和非基本类型)使用sizeof运算符,需要放在 unsafe 代码块中。

  1. unsafe
  2. {
  3. Console.WriteLine(sizeof(Customer));
  4. }

typeof 运算符

返回表示特定类型的 System.Type 对象。如 typeof(string) 返回表示 System.String 类型的Type对象。

可空类型运算符

  1. int? v1 = null;
  2. int? a = v1 + ; // a = null

空合并运算符

  1. int? v1 = null;
  2. v1 = v1 ?? ;
  3. Console.WriteLine(v1);

运算符优先级

一般情况避免利用运算符优先级来生成正确结果,用圆括号指定运算符执行顺序。

类型安全

中间语言(IL)对代码实现强制实现强类型。

强类型语言在没有强制类型转换前,不允许两种不同类型的变量相互操作。

类型转换

  1. byte byte1 = ;
  2. byte byte2 = ;
  3. byte count = byte1 + byte2;
  4. Console.WriteLine(count);

这里编译时,提示您 byte count 改成 int count。只是因为 两个 byte类型 相加 返回 int 类型,这时就需要类型转换了。

1、隐式转换

只要能保证值不会发生任何变化,类型转换就开自动(隐式)进行。

  1. long count = byte1 + byte2;

2、显示转换类型

  1. byte count =(byte) (byte1 + byte2);

要小心的时候显示转换类型,还要注意防止丢失数据。更不能转换 null 。

如果要 字符串 转换 为 int 时

  1. string str = "";
  2. int i = int.Parse(str);
  3. str = i.ToString();

装箱和拆箱

装箱用于描述把一个值类型转换为引用类型。

拆箱把引用类型转换为值类型。

比较引用类型的相等性

ReferenceEquals

两个版本 Equals

比较运算符(==)

1、ReferenceEquals

ReferenceEquals是一个静态方法,测试两个引用类的同一个实例,判断两个引用是否包含内存中的相同地址。

2、虚函数 Equals

因为是虚函数,所以需要在类中重写它,比较。比较方式可以通过值。如果需要用类的实例用作字典中的键,那么需要重写 Object.GetHashCode() 的方式,注意此方式效率非常低的。

3、静态函数 Equals

有两个参数,如果两个引用实际上引用了某个对象,它就调用虚函数 Equals 实例方法。这表示重写了 虚函数 Equals ,也重写了静态版本函数。

4、比较运算符 ==

比较值和比较引用。

ReferenceEquals 用于比较引用,Equals 用于比较值,比较运算符看作一个中间项。ReferenceEquals应用值类型时,总是返回false。因为值类型需要装箱到对象中。

System.ValueType 提供的 Equals 的默认重写版本肯定足以应付绝大多数自定义的结构,但仍可以针对自己的接口再次重写它,以提供性能。

运算符重载

重载不仅仅限于算术运算符。还可以 重载比较运算符 ==、< 。等 语句 if(a==b) 默认比较引用,对于 string,比较字符串是否相同。

  1. struct Vector
  2. {
  3. public double x, y, z;
  4.  
  5. public Vector(double x, double y, double z)
  6. {
  7. this.x = x;
  8. this.y = y;
  9. this.z = z;
  10. }
  11.  
  12. public Vector(Vector rhs)
  13. {
  14. x = rhs.x;
  15. y = rhs.y;
  16. z = rhs.z;
  17. }
  18.  
  19. public override string ToString()
  20. {
  21. return x + " " + y + " " + z;
  22. }
  23.  
  24. public static Vector operator +(Vector lhs, Vector rhs)
  25. {
  26. Vector result = new Vector(lhs);
  27. result.x += rhs.x;
  28. result.y += rhs.y;
  29. result.z += rhs.z;
  30. return result;
  31. }
  32.  
  33. public static Vector operator *(Vector lhs, double rhs)
  34. {
  35. return new Vector(rhs * lhs.x, rhs * lhs.y, rhs * lhs.z);
  36. }
  37. }

一般运算符左边参数命名 lhs,运算符右边命名 rhs。

  1. Vector vector1, vector2, vector3;
  2. vector1 = new Vector(4.0, 3.0, 1.0);
  3. vector2 = new Vector(4.0, -3.0, -1.0);
  4. vector3 = vector1 + vector2;
  5. Console.WriteLine(vector3);

与C++语言不同,C#不允许重载 "=" 运算符,但如果重载 "+" 运算符,编译器自动使用 "+" 运算符的重载执行 += 匀速符操作。

比较运算符重载

  • == 和 !=
  • > 和 <
  • >= 和 <=

如果重载了 "==",就必须重载 "!=" 。另外,比较运算符必须返回布尔类型的值。

重载 "==" 和 "!=" 时,必须重载 System.Object 中继承 Equals 和 GetHashCode 方法,否则会产生一个编译警告。原因是Equals方法实现与"=="运算符相同类型的相等逻辑。

  1. public static bool operator ==(Vector lhs, Vector rhs)
  2. {
  3. if (lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z)
  4. {
  5. return true;
  6. }
  7. else
  8. {
  9. return false;
  10. }
  11. }
  12.  
  13. public static bool operator !=(Vector lhs, Vector rhs)
  14. {
  15. return !(lhs == rhs);
  16. }
  17.  
  18. public override bool Equals(object obj)
  19. {
  20. return base.Equals(obj);
  21. }
  22.  
  23. public override int GetHashCode()
  24. {
  25. return base.GetHashCode();
  26. }

用户自定义的类型强制重载

c#允许定义自己的数据类型(结构和类),并可以在自定义数据类型之间进行类型强制转换。

  1. public static implicit operator float(Currency value)
  2. {
  3. return (float) value;
  4. }

这里定义的类型强制转换可以隐式地把Currency型的值转换为float型。

implicit 声明 数据类型转换为隐式的,编译器就可以隐式或显式的使用这个转换。

explicit 声明为显式的使用它。

  1. public static explicit operator Celsius(Fahrenheit fahr)
  2. {
  3. return new Celsius((5.0f / 9.0f) * (fahr.degrees - ));
  4. }
  5.  
  6. Fahrenheit fahr = new Fahrenheit(100.0f);
  7. Console.Write("{0} Fahrenheit", fahr.Degrees);
  8. Celsius c = (Celsius)fahr;

类型强制转换必须同时声明为 public 和 static。

https://msdn.microsoft.com/zh-cn/library/xhbhezf4.aspx

C++中,类型强制转化针对于类的实例成员。

示例

  1. struct Currency
  2. {
  3. public uint Dollars;
  4. public ushort Cents;
  5.  
  6. public Currency(uint dollars, ushort cents)
  7. {
  8. this.Dollars = dollars;
  9. this.Cents = cents;
  10. }
  11.  
  12. public override string ToString()
  13. {
  14. return string.Format("${0}.{1,-2:00}", Dollars,Cents);
  15. }
  16.  
  17. // 隐式转换
  18. public static implicit operator float(Currency value)
  19. {
  20. return value.Dollars + (value.Cents / 100.0f);
  21. }
  22.  
  23. // 显示转换
  24. public static explicit operator Currency(float value)
  25. {
  26. uint dollars = (uint)value;
  27. ushort cents = (ushort)((value - dollars) * );
  28. return new Currency(dollars, cents);
  29. }
  30.  
  31. }
  32.  
  33. static void Main(string[] args)
  34. {
  35. try
  36. {
  37. Currency balance = new Currency(,);
  38.  
  39. Console.WriteLine(balance); // 转换为 float
  40. Console.WriteLine("balance is " + balance); // 隐式调用 toString
  41. Console.WriteLine("balance is (using ToString()) " + balance.ToString()); // 显示调用 toString
  42.  
  43. float balance2 = balance; // 隐式转为 float
  44.  
  45. Console.WriteLine("After converting to float, = " + balance2);
  46.  
  47. balance = (Currency) balance2; // 显示转为 Currency
  48.  
  49. Console.WriteLine("After converting back to Currency, = " + balance);
  50. Console.WriteLine("Now attempt to convert out of range value of " +
  51. "-$50.50 to a Currency:");
  52.  
  53. checked
  54. {
  55. balance = (Currency)(-50.50); // 显示转为 Currency
  56. Console.WriteLine("Result is " + balance.ToString());
  57. }
  58. }
  59. catch(Exception e)
  60. {
  61. Console.WriteLine("Exception occurred: " + e.Message);
  62. }
  63.  
  64. Console.ReadLine();
  65. }

类型转换的语法对于结构和类一样的。

类之间的类型强制转换

定义不同结构或类的实例之间的类型强制是完全合法,也有限制:

  • 如果某个类派生自另一个类,就不能定义这两个类之间的类型强制转换(因为这些类型转换已存在)。
  • 类型强制必须在源数据类型或目标数据类型的内部定义。

C#要求把类型强制转换的定义放在源类或目标类的内部。因为这样可以防止第三方类型强制转换引入类中。

基类和派生类之间的类型强制转换

MyBase 和 MyDerived。其中 Myderived 直接或间接派生自 MyBase 类。

  1. MyDerived derivedObject = new MyDerived();
  2. MyBase baseCopy = derivedObject;

MyDerived 隐式地强制转换为 MyBase

  1. MyBase derivedObject = new MyDerived();
  2. MyBase baseObject = new MyBase();
  3. MyDerived derivedCopy1 = (MyDerived) derivedObject; // OK
  4. MyDerived derivedCopy2 = (MyDerived) baseObject; // Throws exception

基类是不可以强制转为派生类。

装箱和拆箱数据类型强制转换

  1. object derivedObject = new Currency();
  2. object baseObject = new object();
  3. Currency derivedCopy1 = (Currency) derivedObject; // OK
  4. Currency derivedCopy2 = (Currency) baseObject; // Throws exception

多重类型转换

  1. Currency balance = new Currency();
  2. long amount = (long) balance;
  3. double amountD = balance;

Currency 定义了一个 float 的隐式转换,编译器又知道如何显式地从 float 强制转换为 long。所以 IL代码 首先把 balance 转换为 float,在把结果转换 long。类似这样。

  1. long amount = (long) (double)balance;

C# 运算符和类型强制转换(6) 持续更新的更多相关文章

  1. C#高级编程9-第7章 运算符和类型强制转换

    运算符和类型强制转换 1.运算符 运算符的简化操作 条件运算符: if-else的简化操作,也称三元运算符.如果条件为真,返回一个值,为假返回另外一个值. condition?true_value:f ...

  2. C#高级编程 (第六版) 学习 第六章:运算符和类型强制转换

    第六章 运算符和类型强制转换 1,运算符 类别 运算符 算术运算符 + - * / % 逻辑运算符 & | ^ ~ && || ! 字符串连接运算符 + 增量和减量运算符 ++ ...

  3. C#学习笔记二 (资源托管,泛型,数组和元组,运算符和类型强制转换)

     托管和非托管资源 1.托管资源是指GC管理的内存空间,非托管资源是指文件句柄,网络连接,数据库连接等. 2.方法中临时申请的变量,被存放在栈中.栈存储非对象成员的值数据.例如在方法中有B b=new ...

  4. C#高级编程笔记 2016年10月8日运算符和类型强制转换

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

  5. 【读书笔记】C#高级编程 第七章 运算符和类型强制转换

    (一)运算符 类别 运算符 算术运算符 + - * / % 逻辑运算符 & | ^ ~ && || ! 字符串连接运算符 + 增量和减量运算符 ++ -- 移位运算符 < ...

  6. 使用 as 和 is 运算符安全地进行强制转换

    由于对象是多态的,因此基类类型的变量可以保存派生类型. 若要访问派生类型的方法,需要将值强制转换回该派生类型. 不过,在这些情况下,如果只尝试进行简单的强制转换,会导致引发 InvalidCastEx ...

  7. 如何:使用 as 和 is 运算符安全地进行强制转换(C# 编程指南)

    如何:使用 as 和 is 运算符安全地进行强制转换(C# 编程指南) 由于对象是多态的,因此基类类型的变量可以保存派生类型.若要访问派生类型的方法,需要将值强制转换回该派生类型.不过,在这些情况下, ...

  8. C语言指针类型 强制转换

    关于C语言指针类型 强制转换  引用一篇文章: C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值.不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个 ...

  9. OC中的类型强制转换

    在Objective-C中,以数字格式组成的字符串经常需要转换为NSNumber对象后再使用.例如有一个字符串对象@"111.22",需要转为NSNumber对象,最简单的方法就是 ...

随机推荐

  1. IDEA 启动项目 很慢,总会到某个点进行延迟卡顿。

    最开始的我解决的方式 clean 项目 忙完后,闲暇时间想起这个问题,然后进行 面向百度,发现了问题所在 参考文档:https://www.cnblogs.com/zhangzhonghui/p/11 ...

  2. PL/SQL developer 11.0注册码

    PL/SQL developer 11.0注册码:product key:lhsw85g33x4p7leqk63hy8q28ffxzzvbxlserial No:193085password:xs37 ...

  3. Linux系列(16)之系统资源的观察

    1.系统资源观察 1.观察内存使用情况:free 格式: free //默认显示的单位为KBytes,显示系统的内存容量 free  [-b | -k | -m | -g | -h]  [-t]  [ ...

  4. Win7原装ISO镜像封装USB3.0&网卡驱动

    Win7原装ISO镜像封装USB3.0&网卡驱动   最新购买的电脑是Windows10系统,想装回Windows7,但是装Windows7发现网络适配器没出现,如果没有USB2.0接口,US ...

  5. javaSE 笔记一

    java 环境变量配置 步骤:   右键[计算机]图标 –>[属性]–>[高级系统设置]–>[环境变量]   在"系统变量"里找到"Path" ...

  6. analysis_tools

  7. S02_CH10_ User GPIO实验

    S02_CH10_ User GPIO实验 在之前的第四章课程中,我们详细的讲解了如何在VIVADO软件下封装一个简单的流水灯程序.在ZYNQ开发过程中,有时候我们可能会需要与ARM硬核进行通信,在这 ...

  8. Linux Centos7 离线安装docker 【官网翻译和注释】

    Centos7的Docker安装 需要一个维护版本的centos7,所以6不行. 卸载旧版本 旧版本的docker被称为 docker or docker-engine 如果存在请删除它们. sudo ...

  9. poj 1753高斯

    和前面的开关问题差不多,就是要理解一下我们方程等号的右端代表的含义是什么.我们建立的方程是想让对位的位置变或者不变,然后生成增广矩阵的时候要多注意一点. ac代码: #include #include ...

  10. 9-MySQL DBA笔记-测试实践

    第9章 测试实践 在第8章中介绍了测试所需要的理论知识,本章将为读者讲述实际的测试过程.实际测试一般包括硬件测试.MySQL基准测试及应用服务压力测试,下面将分别讲述这三方面的内容.此外,测试工具的选 ...