对于操作符,我们并不陌生,例如+,-,*,%等二元操作符,以及++,!等一元操作符。但是对于非基元类型,我们需要通过一些自定义方法才能使用这些操作符。今天主要和大家分享关于操作符重载和转换操作符的知识。


一、操作符重载方法

CLR并不知道操作符,操作符重载对于它来说只是一些方法而已。但是CLR规定了语言应该如何公开操作符重载,每种编程语言自行决定是否支持操作符重载。

定义操作符重载方法注意两点:

  • CLR规范要求操作符重载方法必须是 public static 类型。
  • C#要求操作符重载方法必须有一个参数的类型和当前定义这个方法的类型相同。否则会产生编译错误

操作符重载实例

我们为非基元类型Complex重载操作符 “+”.

定义之后,可以使非基元类型Complex方便的进行+操作。

Sepecialname标记

ILDaxm.exe查看Complex类的元数据,发现产生了一个op_Addition项。如果重载其他操作符,也会自动产生相应的specialname标记。

在编译过程中,当代码中出现“+”操作符时,编译器会自动检查op_Addition的specialname标记,并且检测参数类型兼容性。

下面两个表是C#允许重载的一元操作符和二元操作符。简单了解一下就好,没必要强记。

二、转换操作符方法

当两个非基元类型的实例需要相互转换时,我们需要定义转换操作符方法。转换操作符是指将对象从一个类型转换成另一个类型的方法。

两大规定

  • CLR要求转换操作符重载方法必须是public static 方法。
  • C#要求参数类型和返回类型必须至少有一个与定义转换方法的类型相同。

另外,为了完成转换操作,我们应该在类型内定义两类方法:

  • 实例公共构造器。参数是源类型的实例
  • 无参公共实例方法Toxxx。该方法将定义类型的实例转换成xxx类型。

转换操作符例子

为Rational(有理数)类型定义转换操作符,方便与Int32类型实例进行相互转换。

implicit和explicit

在这个例子中,我们定义了两种转换操作符方法:implicit关键字表示在源代码中不需要进行显式转型;explicit关键字表示进行显式转型时才调用该方法。Operator关键字表明该方法是一个转型操作符。

使用ILDasm.exe查看,

可以发现添加了两个方法:op_Explicit和op_Implicit。只有当转换后不丢失精度的前提下,才能进行隐式转换;如果会发生精度丢失,则只能定义为显式转换。

定义完成之后我们就可以方便的进行转型调用了。

static void Main(string[] args)
        {
            Rational r1 = 5;            // 隐式转换
            Int32 x = (Int32)r1;       // 显示转换
        }

关于重载

在上面的例子中,实际上一个类型经常会和多个类型实例进行转换操作,此时就需要再定义其他转换操作符,例如public static explicit operator Single(Rational r),也就是进行方法重载。对于重载,我们并不陌生,特殊之处在于这两个explicit重载方法仅仅通过返回值类型不同来区分的。

CLR允许定义多个同名方法,只要每个方法的参数或者返回值类型有所区别即可。但是在C#判断方法的唯一性时,除了方法名称外只考虑参数的区别,而忽略掉方法的返回类型。所以,上面的两个重载方法仅有返回类型的差异实际上是C#放宽限制的特例。

CLR via C#(08)-操作符的更多相关文章

  1. CLR 初步

    1. 源代码编译为托管模块 程序在.NET框架下运行,首先要将源代码编译为 托管模块.CLR是一个可以被多种语言所使用的运行时,它的很多特性可以用于所有面向它的开发语言.微软开发了多种语言的编译器,编 ...

  2. CLR via C#(03)- 对象创建和类型转换

    一. 创建对象 CLR要求用new操作符创建对象,这个操作符在编译时产生的IL指令为newobj.例如: Student XiaoJing=new Student(“XiaoJing”,”1986”) ...

  3. CLR via C#深解笔记四 - 方法、参数、属性

    实例构造器和类(引用类型) 构造器(constructor)是允许将类型的实例初始化为良好状态的一种特殊方法.构造器方法在“方法定义元数据表”中始终叫.ctor. 创建一个引用类型的实例时: #1, ...

  4. C#构造函数、操作符重载以及自定义类型转换

    构造器 构造器(构造函数)是将类型的实例初始化的特殊方法.构造器可分为实例构造器和类型构造器,本节将详细介绍有关内容. 实例构造器 顾名思义,实例构造器的作用就是对类型的实例进行初始化.如果类没有显示 ...

  5. CLR via c#读书笔记五:方法

    注:书本第8章:方法 实例构造器和类(引用类型) 构造器方法在“方法定义元数据表”中始终叫做.ctor(constructor的简称). 构造引用类型的对象,在调用类型的实例构造器之前,为对象分配的内 ...

  6. CLR - 设计类型

    前言 好记性不如烂“笔头”系列... 目录 类型基础 基元类型.引用类型和值类型 类型与成员 常量与字段 方法 类型基础 “运行时”要求每个类型最终都从System.Object 类型派生. 由于所有 ...

  7. 应用服务器GC回收常见问题总结

    近一段时间多次发现因GC问题造成系统性能问题(应用服务间歇性响应缓慢.应用服务器CPU占用较高等),在此总结一下: 1.代码中直接调用GC.Collect() 2.字符串等操作频繁的内存申请 3.频繁 ...

  8. 记一次 .NET 某工控自动化控制系统 卡死分析

    一:背景 1. 讲故事 前段时间遇到了好几起关于窗体程序的 进程加载锁 引发的 程序卡死 和 线程暴涨 问题,这种 dump 分析难度较大,主要涉及到 Windows操作系统 和 C++ 的基础知识, ...

  9. 记一次 .NET 某数控机床控制程序 卡死分析

    一:背景 1. 讲故事 前段时间有位朋友微信上找到我,说它的程序出现了卡死,让我帮忙看下是怎么回事? 说来也奇怪,那段时间求助卡死类的dump特别多,被迫训练了一下对这类问题的洞察力 ,再次声明一下, ...

随机推荐

  1. Android学习笔记(二十)——自定义内容提供器

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 如果我们想要实现跨程序共享数据的功能,官方推荐的方式就是使用内容提供器,可以通过新建一个类去继承 Conten ...

  2. [codevs1027]姓名与ID

    [codevs1027]姓名与ID 试题描述 有N个人,各自有一个姓名和ID(别名).每个人的姓名和ID都没有重复.这些人依次进入一间房间,然后可能会离开.过程中可以得到一些信息,告知在房间里的某个人 ...

  3. 多通道(Multichannel)单通道(singlechannel)图像概念梳理

    在做机器视觉时,常常要将一个多通道图像分离成几个单通道图像或者将几个单通道图像合成一个多通道图像,以方便图像处理,但是.写这篇博客,是为加深对这两个概念的理解,下面会给出部分OpenCV对单通道与多通 ...

  4. HDU 3535 分组混合背包

    http://acm.hdu.edu.cn/showproblem.php?pid=3535 题意:有n组工作,T时间,每个工作组中有m个工作,改组分类是s,s是0是组内至少要做一件,是1时最多做一件 ...

  5. 20 BasicTaskScheduler0 基本任务调度类基类(二)——Live555源码阅读(一)任务调度相关类

    这是Live555源码阅读的第二部分,包括了任务调度相关的三个类.任务调度是Live555源码中很重要的部分. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/ol ...

  6. Python自动化之sqlalchemy复合外键

    复合外键用法 metadata = MetaData(engine) classedu = Table('classedu', metadata, # Column('qq', BigInteger, ...

  7. 【架构】MQTT/XMPP/GCM 等参考资料

    https://www.zhihu.com/question/29138530 https://segmentfault.com/q/1010000002598843/a-10200000026014 ...

  8. Oracle 数据操作

    查询及删除重复记录的SQL语句   1.查找表中多余的重复记录,重复记录是根据单个字段(Id)来判断   select * from 表 where Id in (select Id from 表 g ...

  9. C# 毕业证书打印《四》

    数据存储,读取控件在Panel中的位置,将控件的位置保存到xml文件中. /// <summary> /// 将当前格式写入xml /// </summary> /// < ...

  10. JavaScript——Window对象

    1.serTimeout()和setinterval()可用于注册在指定的时间之后单词或者重复调用的函数. 2.window对象的location属性引用的是Location对象,表示该窗口当前显示的 ...