龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C#开发 >

C#中自增、自减操作符重载是个怎么回事儿

时间:2011-04-12 23:18来源:未知 作者:admin 点击:
分享到:
在 C# 中,重载 自增 、 自减 操作符的语法并没有什么特殊之处,如下: public static SomeType operator ++(SomeTypesome) { //具体实现 } 对于C#中的自增、自减操作符重载,无论前缀式或是后缀式,

C#中,重载自增自减操作符的语法并没有什么特殊之处,如下:

  1. public static SomeType operator ++(SomeType some)  
  2. {   
  3. //具体实现  

对于C#中的自增、自减操作符重载,无论前缀式或是后缀式,都统统只需要一个实现。也就是说无论我是这样:someType++,还是这样:++someType使用SomeType类型的自增重载,上述代码中的实现都完全足够完成任务。但是,前缀式++与后缀式++的行为毕竟不同,为什么他们只需要一份同样的实现就可以达到我们需要的目的了呢?

另外,重载操作符的第一原则就是不应该改变操作数对象,而应该返回一个新的对象。否则不仅很可能会令那些使用我们的重载操作符的客户产生困惑,而且更有可能会在调试代码的时候出现意想不到的情况。那么对于自增和自减操作符,我们是否也需要遵从此原则呢?我们又怎么能在不修改操作数的情况下,对操作数自增或者自减呢?考虑如下的实现:

  1. class SomeType   
  2. {   
  3. public int Number   
  4. getset;  
  5. }   
  6. public static SomeType operator ++(SomeType s)   
  7. {  
  8. s.Number++;   
  9. return s;   
  10. }} 

这里直接修改了操作数,并且直接返回了修改之后的操作数实例。

当我们使用SomeType的前缀自增重载时:

  1. SomeType instance = new SomeType();  
  2. instance.Number = 1;  
  3. ++instance; 

如我们所预料的,操作符重载的方法体会被执行。而且instance也确实会按照理想的方式自增。我们再来看后缀自增操作:

  1. SomeType instance1 = new SomeType();  
  2. instance1.Number = 1;  
  3. SomeType instance2 = instance1++; 

不严谨的思维让我们很容易认为,现在instance1的Number应该是2,而instance2的Number应该是1。但是,事不如人愿,实际上现在的instance1和instance2的Number都是2!

这到底是为什么呢?

其实是这样的,相比其他我们司空见惯的重载操作符如+和-,编译器会对重载的自增和自减操作符做一些额外的处理。在我们使用自增重载的时候,如++instance,++重载的方法体会被执行。然而我们没有想到的是,在操作符重载方法被执行完成之后,instance会被自动赋值为操作符重载方法的返回值!而这一切都是编译的时候就安排好了的。

也就是说,如果SomeType是引用类型,则在执行完++instance语句之后,instatnce会指向那个被自增重载操作符方法所返回的对象实例。而如果SomeType是值类型,那么instance会被按照C#值类型的标准赋值方式被重载操作符方法返回的值类型赋值,也就是逐字段赋值。

当我们使用前缀式时,这一切都工作的很好。但是当我们使用后缀式时,问题就来了。在上面的使用后缀自增的例子里,首先执行了instance1的自增操作,不过接下来,实际上是使用了instance1在执行自增操作前的一个副本(对于引用类型,使用引用的副本;对于值类型,使用整个结构的副本)来对instance2赋值的。

因为我们在SomeType的自增重载的实现中,直接对操作数进行了修改,并且返回了原操作数。所以这样一来,现在instance1和instance2现在指向的都是原操作数的实例,他们有同样的Number也就不足为怪了。

另一个SomeType的自增重载版本是这样的:

  1. public static SomeType operator ++(SomeType s)   
  2. {   
  3. var result = new SomeType();   
  4. result.Number++;   
  5. return result;   

这个版本的实现遵循了“不应该在操作符重载中修改操作数”的原则。如果使用了这个版本的自增重载,在上述后缀式自增的例子中,会和我们预期的一样:instance1的Number是2,而instance1的Number是1。

我想,在很多情况下(特别是当SomeType是值类型时),这会是您希望得到的结果,也同样是您代码的消费者所预期的结果。

好吧,对于自增和自减操作符,我们这样理解可能会更容易一些:例如语句“instance2 = instance1++;”,并不是将自增重载方法的返回值赋值给左值instance2,而是将自增重载方法的返回值赋值给instance1。

注意:自增重载方法的返回值是用来赋值给调用该重载方法的操作数的!(如果您有C++的背景,这一点可能不太容易接受)


精彩图集

赞助商链接