1、运算符重载:运算符重重载的关键是在对象上不能总是只调用方法或属性,有时还需要做一些其他工作,例如,对数值进行相加、相乘或逻辑操作等。例如,语句if(a==b)。对于类,这个语句在默认状态下会比较引用 a 和 b 。检测这两个引用是否指向内存中的同一个地址,而不是检测两个实例是否包含相同的数据。然而对于 string 类,这种操作就会重写,于是比较字符串实际上就是比较每个字符串的内容。可以对自己的类进行这样的操作。 对于结构,“==” 运算符在默认状态下是不做任何工作。试图比较两个结构,看看它们是否相等,就会产生一个编译错误。除非显示地重载了“==”,告诉编译器如何进行比较。

  运算符的工作方式

  • int myInteger=3;
    uint myUnsignedInt=2;
    double myDouble=4.0;
    long myLong=myInteger+myUnsignedInt;
    double myOtherDouble=myDouble+myInteger;

    当编译器遇到下面这行代码时会发生什么情况:

  • long myLong=myInteger+myUnsignedInt;

    编译器知道它需要把两个整数加起来,并把结果赋予一个long 型变量。调用一个方法把数字加在一起时,表达式myInteger +myUnsignedInt 是一种非常直观和方便的语法。该方法接受两个参数 myInteger 和myUnsignedInt, 并返回他们的和。所以编译器完成的任务与任何方法调用一样——它会根据参数的类型查找最匹配的“+”运算符重载,这里是带两个整数参数的“+”运算符重载。与一般的重载方法一样,预定义的返回类型不会因为编译器所调用方法的哪个版本而影响编译器的选择。

  • double myOtherDouble=myDouble+myInteger;

    在这个例子中,参数是一个double 类型的数据和一个 int 类型的数据,但“+”运算符没有带这种复合参数的重载形式,所以编译器认为,最匹配的“+”运算符重载是把两个 double 作为其参数的版本,并隐式地把int强制转换为 double。 把两个 double 加在一起与把两个整数加在一起完全不同,浮点数存储为一个尾数和一个指数。把她们加在一起要按位移动一个double的尾数,从而使两个指数有相同的值,然后把尾数加起来,移动所得尾数的数,调整其指数,保证答案有尽可能高的精度。

  • 下面是运算符重载的例子 Vector结构。(在运算符重载时,结构和类的工作方式是一样的。)
  • Vector 是一个三维矢量比如 a(1.0,2.0,3.0) b(-1.0,3.0,-4.0) 相加得到的结果 c=a+b 为(0,5,-1)
  •  1 namespace Com.Test.Yinxi
    2 {
    3 struct Vector
    4 {
    5 public double x,y,z;
    6
    7 public Vector(double x,double y,double z)
    8 {
    9 this.x=x;
    10 this.y=y;
    11 this.z=z;
    12 }
    13
    14 public Vector(Vector rhs)
    15 {
    16 x=rhs.x;
    17 y=rhs.y;
    18 z=rhs.z;
    19 }
    20
    21 public override string ToString()
    22 {
    23 return "("+x+", "+y+", "+z+")";
    24 }

    下面是Vector的运算符提供运算符重载支持

  • public static Vector operator +(Vector lhs,Vector rhs)
    {
    Vector result=new Vector(lhs);
    result.x+=rhs.x;
    result.y+=rhs.y;
    reault.z+=rhs.z; return result;
    }

    c#要求所有的运算符重载都声明为public 和 static ,这表示他们与它们的类或结构相关联,而不是与某个特定实例相关联,所以运算符重载的代码体不能访问非静态成员,也不能访问this标识符;这是可以的,因为参数提供了运算符执行其任务所需要知道的所有输入数据。

   完整代码如下:

  •  

     1 using System;
    2
    3 namespace CSharpTest
    4 {
    5 class OperatorTest
    6 {
    7 public double x, y, z;
    8
    9 public OperatorTest(double x, double y, double z)
    10 {
    11 this.x = x;
    12 this.y = y;
    13 this.z = z;
    14 }
    15
    16 public OperatorTest(OperatorTest oper)
    17 {
    18 x = oper.x;
    19 y = oper.y;
    20 z = oper.z;
    21 }
    22
    23 public override string ToString()
    24 {
    25 return "(" + x + ", " + y + ", " + z+")";
    26 }
    27 public static OperatorTest operator + (OperatorTest lhs, OperatorTest rhs)
    28 {
    29 OperatorTest oper = new OperatorTest(lhs);
    30 oper.x += rhs.x;
    31 oper.y += rhs.y;
    32 oper.z += rhs.z;
    33 return oper;
    34 }
    35
    36 public static void Main(string[] args)
    37 {
    38 OperatorTest oper1 = new OperatorTest(1.0, 2.0, 3.0);
    39 OperatorTest oper2 = new OperatorTest(-1.0, -3.5, -5.0);
    40 //OperatorTest oper3 = new OperatorTest(2.0, 3.0, 1.0);
    41 OperatorTest oper3;
    42 oper3 = oper1 + oper2;
    43 Console.WriteLine(oper1.ToString());
    44 Console.WriteLine(oper2.ToString());
    45 Console.WriteLine(oper3.ToString());
    46
    47 }
    48 }
    49
    50 }

    算术运算符重载的 声明方式

  • //1、
    public static double operator *(operatorTest lhs,operatroeTest rhs)
    {
    //......
    }
    可以根据自己所需要的,所要得到的重载结果 相应的改变 double 函数返回值

   比较运算符的重载

   C#中共有6个比较运算符 它们分为3对

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

 c#要求成对重载比较运算符,即,如果重载了“==”,也就必须重载“!=”;否则会产生编译错误。另外,比较运算符必须返回布尔类型的值。这是它们与算术运算符的根本区别,

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

除了这些区别外,重载比较运算符所遵循的规则与重载算术运算符相同。但比较两个数并不像想象的那么简单,例如,如果只比较两个对象引用,就是比较存储对象的内存地址。比较运算符很少进行这样的比较,所以必须编写代码重载运算符,比较对象的值,并返回相应的布尔结果。

  •  1 public static bool operator ==(OperatorTest lhs,OperatorTest 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 }

    这种方式仅根据矢量元素的值,来对它们进行相等性的比较。对于大多数结构,这就是我们希望的,但在某些情况下,可能需要仔细考虑相等的含义。例如,如果有嵌入的类,那么是应比较引用是否指向同一个对象(浅度比较),还是应比较对象的值是否相等(深度比较)?

  • 浅度比较是比较对象是否指向内存中的同一个位置,而深度比较是比较对象的值和属性是否相等。应根据具体情况进行相等检查,从而有助于确定要验证什么。
  • 不要通过调用从 System.Object 中继承的 Equals()方法的实例版本,来重载比较运算符。如果这么做,在 objA 是 null 时判断 (objA==objB),就会产生一个异常,因为.NET 
    运行库会试图判断null.Equals(objB)。采用其他方法(重写 Equals()方法以调用比较运算符)比较安全
    public static bool operator !=(OperatorTest lhs,OperatorTest rhs)
    {
    return !(lhs==rhs);

可以重载的运算符:

类别 运算符 限制 
算术二元运算符 + 、*、  /、 -、 % 无  
算术一元运算符 +、 -、 ++、 --
按位二元运算符 &、|、^、<<、>>
按位一元运算符 !、~、true、false true 和 false 必须成对重载
比较运算符 ==、!=、>=、<=、<、> 必须成对重载
赋值运算符 += 、-=、 *=、 /=、 >>=、 <<=、 %=、 |=、 ^= 不能显式地重载这些运算符,在重写单个运算符(如+,-,%等)时,它们会被隐式地重写。
索引运算符 [] 不能直接重载索引运算符。索引器成员类型允许在类和结构上支持索引运算符
数据类型强制转换运算符 () 不能直接重载类型强制转换运算符。用户定义的类型强制转换允许定义定制的类型强制转换行为

2、用户定义的类型强制转换

  定义类型强制转换的语法类似于重载运算符,类型强制转换在某种情况下可以看做是一种运算符默,其作用是从源类型转换为目标类型。

public static implicit operator float(Currency value)//implicit 隐式  explicit 显式
{
//....
}

  运算符的返回类型定义了类型强制转换操作的目标类型,它有一个参数,即要转换的源对象。这里定义的类型强制转换可以隐式地把Currency 型的值转换为float 型。 注意,如果数据类型转换声明为隐式,编译器就可以隐式或显式地使用这个转换。如果数据类型转换声明为显式,编译器就只能显式地使用它。与其他运算符重载一样,类型强制转换必须同时声明为public 和static。

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

  • 装箱
  • Currency balance =new Currency(,);
    object baseCopy=balance;

    在执行上述隐式地强制转换时,balance的内容被复制到堆上,放在一个装箱的对象上,baseCopy 对象引用被设置为该对象。实际上在后台发生的情况是:在最初定义Currency结构时,.NET Framework 隐式地提供另一个(隐藏的)类,即装箱的Currency 类,它包含于Currency 结构相同的所有字段,但它是一个引用类型,存储在堆上。无论定义的这个值类型是一个结构还是一个枚举,定义它时都存在类似的装箱引用类型,对应于所有的基元值类型,如 int double 和 uint 等。不能也不必再源代码中直接通过编程访问某些装箱类,但在把一个值类型强制转换为object 时,它们实在后台工作的对象。在隐式地把currency转换为object时,会实例化一个装箱的Currency实例,并用Currency结构中的所有数据进行初始化。在上面的代码中,baseCopy对象引用的就是这个已装箱的currency实例。通过这种方式,就可以实现从派生类型到基类型的强制转换,并且,值类型的语法与引用类型的语法一样。

  • 拆箱
  •  object derivedObject=new Currency(,);
    object baseObject=new Object();
    Currency derivedCopy1=(Currency)derivedObject;//可以转换
    Currency derivedCopy2=(Currency)baseObject;//抛出异常

    上述代码的工作方式与前面的引用类型中的代码一样。把derivedObject 强制转换为 Currency 会成功进行,因为derivedObject 实际上引用的是装箱 Currency实例——强制转换的过程是把已装箱的Currency对象的字段复制到一个新的currency 结构中。第二种强制转换会失败,因为 baseObject没有引用已装箱的Currency 对象。

    在使用装箱和拆箱时,这两个过程都把数据复制到新装箱或拆箱的对象上。对装箱对象的操作就不会影响原始值类型的内容。

C#高级编程笔记2016年10月12日 运算符重载的更多相关文章

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

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

  2. C#高级编程笔记 2016年10月26日 MVC入门 Controller

    1.MVC的定义:   Models: Classes that represent the data of the application  and that use validation logi ...

  3. 2016年10月12日 星期三 --出埃及记 Exodus 18:23

    2016年10月12日 星期三 --出埃及记 Exodus 18:23 If you do this and God so commands, you will be able to stand th ...

  4. 2016年10月12日--string、Math类、Random随机数、DateTime、异常保护

    string string.length; //得到string长度 string.Trim(); //去掉string前后的空格 string.TrimStart(); //去掉string前的空格 ...

  5. 2016年10月31日 星期一 --出埃及记 Exodus 19:16

    2016年10月31日 星期一 --出埃及记 Exodus 19:16 On the morning of the third day there was thunder and lightning, ...

  6. 2016年10月30日 星期日 --出埃及记 Exodus 19:15

    2016年10月30日 星期日 --出埃及记 Exodus 19:15 Then he said to the people, "Prepare yourselves for the thi ...

  7. 2016年10月29日 星期六 --出埃及记 Exodus 19:14

    2016年10月29日 星期六 --出埃及记 Exodus 19:14 After Moses had gone down the mountain to the people, he consecr ...

  8. 2016年10月28日 星期五 --出埃及记 Exodus 19:13

    2016年10月28日 星期五 --出埃及记 Exodus 19:13 He shall surely be stoned or shot with arrows; not a hand is to ...

  9. 2016年10月27日 星期四 --出埃及记 Exodus 19:12

    2016年10月27日 星期四 --出埃及记 Exodus 19:12 Put limits for the people around the mountain and tell them, `Be ...

随机推荐

  1. mysql max_allowed_packet 设置过小导致记录写入失败

    mysql根据配置文件会限制server接受的数据包大小. 有时候大的插入和更新会受max_allowed_packet 参数限制,导致写入或者更新失败. 查看目前配置 show VARIABLES ...

  2. web兼容学习分析笔记-margin 和padding浏览器解析差异

    二.margin 和padding浏览器解析差异 只有默认margin的元素 <body>margin:8px  margin:15px 10px 15px 10px(IE7) <b ...

  3. StarUML license key

    参考博客:http://blog.csdn.net/Excing/article/details/48998891 方法 将StarUML/www/license/node/LicenseManage ...

  4. mysql 多版本并发控制

    查看事务隔离级别 SHOW VARIABLES LIKE "%iso%" MVCC 通过给每张表多加两个隐藏列来实现,一个保存了行的创建时间,一个保存了行的过期时间(或删除时间), ...

  5. Oracle11g字符集AL32UTF8修改为ZHS16GBK详解

    此问题发生在数据库迁移过程中.源数据库:自己笔记本上win7 64位系统的oracle11g个人版,字符集ZHS16GBK :目标数据库,HP的sqlserver2008 系统 64位数据库服务器,字 ...

  6. setTimeout和setInterval定时器使用详解测试

    var len=4; while(len--){ var time=setTimeout(function(){ console.log(len); },0); console.log(time); ...

  7. hibernate主键生成策略

    在hibernate中,提供了多种主键生成器(不同的数据库,不同的表结构使用的主键生成策略也不相同),查阅相关资料经过实验总结如下: 1.increment 主键按照数值顺序递增,使用当前实例中最大值 ...

  8. BZOJ 1041: [HAOI2008]圆上的整点

    1041: [HAOI2008]圆上的整点 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3621  Solved: 1605[Submit][Sta ...

  9. div的水平和垂直居中

    CSS实现div的水平居中 div的水平居中可以通过margin设置为0 auto实现. .myDiv { width: 200px; height: 100px; margin: 0 auto; } ...

  10. vim简单使用

    摘自:http://blog.csdn.net/niushuai666/article/details/7275406   一.安装vim   sudo apt-get install vim   二 ...