.NET执行==运算符时的转换处理

这个问题我最早发在CSDN论坛上,经过很多网友的热心帮助,最后我得出了一个结论。对不对我不知道,但是我有相当的自信是这样的,希望有人能告诉我吧。
例子代码如下:
using System;
using System.Collections;


struct Digit
{
    
byte value;

    
public Digit(byte value)
    {
        
if (value > 9throw new ArgumentException();
        
this.value = value;
    }

    
public static implicit operator byte(Digit d)
    {
        Console.WriteLine(
"Conversion occured");
        
return (byte)((int)d.value + 1);
    }
}

class app
{
    
static void Main()
    {
        Digit d 
= new Digit(5);
        
byte b = d;
        Console.WriteLine(b 
== d);
    }
}
运行这段代码,结果是什么呢?
Conversion occured
Conversion occured
True
刚开始我百思不得其解,因为d的值是5,而b的值是6,怎么会相等呢?后来在网友的帮助下,我得出了下面的看法:
首先,==运算符两边的两个操作数都是值类型,所以==运算符只比较其值是否相等即可。
然后,也是最重要的一点就是,==运算符两边的操作数的类型必须要一致,并且这个类型要重载了==运算符的实现。很显然,我自定义的Digit结构并没有重载==的实现。而据我推测,byte类型作为c#的基元类型,是实现了==运算符的。因此,在这里,CLR在执行的时候会将Digit转换到byte类型再比较,而转换的结果比转换前的值要大1,所以两者都是6了(注意转换后d的值还是5,但是==比较的是b和将d转换后的返回值)。结果就是True了。这也可以解释为什么会出现两个“Conversion occured”了。因为进行了两次隐式转换,为变量b赋值时进行了一次,==比较的时候又进行了一次。通过单步执行可以更清楚地看到这个过程。

为了更加深入研究这个例子,并且证明我前面的猜测:==运算符两边的操作数的类型必须要一致,并且这个类型要重载了==运算符的实现。我把代码做了一点小的修改,Main方法替换为下面的代码:
        Digit d = new Digit(5);
        Digit d2 
= new Digit(6);
        Console.WriteLine(d 
== d2);
按照我的猜测,虽然==运算符两边都是Digit,而Digit又没有重载==运算符,但这时并不是不能比较,因为我们在Digit结构中定义了从Digit到byte的隐式转换。所以在执行到==的时候,会分别将d和d2转换到byte类型,再进行比较,即比较6和7了,最后结果当然就是:
Conversion occured
Conversion occured
False
如果我们把Digit定义中到byte的隐式转换注释掉,那么c#编译器就会报如下的错误:
Operator '==' cannot be applied to operands of type 'Digit' and 'Digit'
因为Digit没有重载==运算符,编译器又找不到存在的任何转换(包括隐式的和显式的),所以就会报错。

这个例子告诉我们,如果我们自己定义了结构,而且需要对该结构类型的对象进行==运算,那么我们就要自己定义==运算符,否则结果就可能不是我们预期的那样了:
using System;
using System.Collections;


struct Digit
{
    
byte value;

    
public Digit(byte value)
    {
        
if (value > 9throw new ArgumentException();
        
this.value = value;
    }

    
public static implicit operator byte(Digit d)
    {
        Console.WriteLine(
"Conversion occured");
        
return (byte)((int)d.value + 1);
    }

    
public static bool operator ==(byte b, Digit d)
    {
        
return b == d.value;
    }
    
public static bool operator !=(byte b, Digit d)
    {
        
return !(b == d);
    }
}

class app
{
    
static void Main()
    {
        Digit d 
= new Digit(5);
        
byte b = d;
        Console.WriteLine(b 
== d);
    }
}
这样,由于我们实现了在byte和Digit类型之间的==运算符,所以就不会像前面那样进行类型转换了,结果也当然是我们预期的那样了:
Conversion occured
False

posted on 2005-07-12 16:24  buaaytt  阅读(1982)  评论(8编辑  收藏  举报

导航