C#锐利体验(8.2)

C#锐利体验(8.2)


Author: 李建忠  &;nbspFrom:Internet


                操作符重载
 
    操作符是C#中用于定义类的实例对象间表达式操作的一种成员。和索引器类似,操作符仍然是对方法实现的一种逻辑界面抽象,也就是说在编译成的IL中间语言代码中,操作符仍然是以方法的形式调用的。在类内定义操作符成员又叫操作符重载。C#中的重载操作符共有三种:一元操作符,二元操作符和转换操作符。并不是所有的操作符都可以重载,三种操作符都有相应的可重载操作符集,列于下表:
 
    一元操作符  - ! "    -- true false
    二元操作符  - * / % &; | ^ << >> == != > < >= <=
    转换操作符 隐式转换()和显式转换()
 
    重载操作符必须是public和static 修饰的,否则会引起编译错误,这在操作符的逻辑语义下是不言而喻的。父类的重载操作符会被子类继承,但这种继承没有覆盖,隐藏,抽象等行为,不能对重载操作符进行virtual sealed override abstract修饰。操作符的参数必须为传值参数。我们下面来看一个具体的例子:
 
  using System;
  class Complex
  {
      double r, v; //r  v i
      public Complex(double r, double v)
      {
          this.r=r;
          this.v=v;
      }
      public static Complex operator  (Complex a, Complex b)
      {
          return new Complex(a.r b.r, a.v b.v);
      }
      public static Complex operator -(Complex a)
      {
          return new Complex(-a.r,-a.v);
      }
      public static Complex operator  (Complex a)
      {
          double r=a.r 1;
          double v=a.v 1;
          return new Complex(r, v);
      }
      public void Print()
      {
          Console.Write(r "  " v "i");
      }
  }
  class Test
  {
      public static void Main()
      {
          Complex a=new Complex(3,4);
          Complex b=new Complex(5,6);
 
          Complex c=-a;
          c.Print();
          Complex d=a b;
          d.Print();
 
          a.Print();
          Complex e=a  ;
          a.Print();
          e.Print();
          Complex f=  a;
          a.Print();
          f.Print();
 
      }
  } 
 
    编译程序并运行可得到下面的输出:
 
    -3  -4i 8  10i 3  4i 4  5i 3  4i 5  6i 5  6i
 
    我们这里实现了一个“ ”号二元操作符,一个“-”号一元操作符(取负值),和一个“  ”一元操作符。注意这里,我们都没有对传进来的参数作任何改变--这在参数是引用类型的变量是尤其重要,虽然重载操作符的参数只能是传值方式。而我们在返回值时,往往需要“new”一个新的变量--除了true和false操作符。这在重载“  ”和“--” 操作符时尤其显得重要。也就是说我们做在a  时,我们将丢弃原来的a值,而取代的是新的new出来的值给a! 值得注意的是e=a  或f=  a中e的值或f的值根本与我们重载的操作符返回值没有一点联系!它们的值仅仅是在前置和后置的情况下获得a的旧值或新值而已!前置和后置的行为不难理解。
 
    操作符重载对返回值和参数类型有着相当严格的要求。一元操作符中只有一个参数。操作符“  ”和“--”返回值类型和参数类型必须和声明该操作符的类型一样。操作符“  - ! "”的参数类型必须和声明该操作符的类型一样,返回值类型可以任意。true和false操作符的参数类型必须和声明该操作符的类型一样,而返回值类型必须为bool,而且必须配对出现--也就是说只声明其中一个是不对的,会引起编译错误。参数类型的不同会导致同名的操作符的重载--实际上这是方法重载的表现。
 
    二元操作符参数必须为两个,而且两个必须至少有一个的参数类型为声明该操作符的类型。返回值类型可以任意。有三对操作符也需要必须配对声明出现,它们是“==”和“!=”,“>”和“<”,“>=”和“<=”。需要注意的是两个参数的类型不同,虽然类型相同但顺序不同都会导致同名的操作符的重载。
 
    转换操作符为不同类型之间提供隐式转换和显式转换,主要用于方法调用,转型表达和赋值操作。转换操作符对其参数类型(被转换类型)和返回值类型(转换类型)也有严格的要求。参数类型和返回值类型不能相同,且两者之间必须至少有一个和定义操作符的类型相同。转换操作符必须定义在被转换类型或转换类型任何其中一个里面。不能对系统定义过的转换操作进行重新定义。两个类型也都不能是object或接口类型,两者之间不能有直接或间接的继承关系--这三种情况系统已经默认转换。我们来看一个例子:
 
  using System;
  public struct Digit
  {
      byte value;
      public Digit(byte value)
      {
          if (value < 0 || value > 9)
              throw new ArgumentException();
          this.value = value;
      }
      public static implicit operator byte(Digit d)
      {
          return d.value;
      }
      public static explicit operator Digit(byte b)
      {
          return new Digit(b);
      }
  } 
 
    上面的例子提供了Digit类型和byte类型之间的隐式转换和显式转换。从Digit到byte的转换为隐式转换,转换过程不会因为丢失任何信息而抛出异常。从byte到Digit的转换为显式转换,转换过程有可能因丢失信息而抛出异常。实际上这也为我们揭示了什么时候声明隐式转换,什么时候声明显示转换的设计原则。不能对同一参数类型同时声明隐式转换和显式转换。隐式转换和显式转换无需配对使用--虽然C#推荐这样做。
 
    实际上可以看到,对于属性,索引器和操作符这些C#提供给我们的界面操作,都是方法的某种形式的逻辑抽象包装,它旨在为我们定义的类型的用户提供一个友好易用的界面--我们完全可以通过方法来实现它们实现的功能。理解了这样的设计初衷,我们才会恰当,正确地用好这些操作,而不致导致滥用和错用。  (2005-6-25:04:39)
 感谢原创者的辛勤劳动,希望对您有所帮助,转载请注明原出处。
 警告:持续变种木马正在发起农历新年攻势!
 您可能对 [C#] 的这些文章也感兴趣:
C#实现所有经典排序算法
使用C#的BitmapData编程实例
用C#编写网络电话
C# 实现 RDLC 自定义报表
C#实现Web代理服务程序
简易C#入门教程
C#中的“Squiggles”特性
C#数字图像探索系列(1)--伪渐变效果原理及应用初级篇
C#数字图像探索系列(2)--渐变二
如何在MFC中调用C#编写的DLL
C# wm6通过udp协议和pc通讯
异步网络编程之图片批量抓取下载(C#)