为什么显式转换为'decimal'会将显式运算符调用为'long'?

时间:2011-11-02 14:30:35

标签: c# implicit-conversion

请考虑以下代码:

class Program
{
    public static explicit operator long(Program x) { return 47; }

    static int Main(string[] args)
    {
        var x = new Program();
        Console.WriteLine((decimal) x);
    }
}

令我惊讶的是,这会输出47;换句话说,即使转换为explicit operator long,也会调用decimal

C#规范中是否有明确说明会发生这种情况(如果是这样,究竟在哪里)或者这是否是我遗漏的其他一些规则的结果?

2 个答案:

答案 0 :(得分:6)

我能想到的唯一解释是编译器足够聪明,可以实现有一个隐式运算符,它将long转换为十进制,它可以用来满足Program和decimal之间的显式转换,当程序只能转换为长。

编辑:我们在这里;数字类型之间的转换内置于语言规范中:

  

6.1.2隐式数字转换

     

隐式数字转换为:

     

·从sbyte到short,int,long,float,double或decimal。

     

·从byte到short,ushort,int,uint,long,ulong,float,   加倍或小数。

     

·从short到int,long,float,double或decimal。

     

·从ushort到int,uint,long,ulong,float,double或   小数。

     

·从int到long,float,double或decimal。

     

·从uint到long,ulong,float,double或decimal。

     

·从long到float,double或decimal。

     

·从ulong到float,double或decimal。

     

·从char到ushort,int,uint,long,ulong,float,double,   或小数。

     

·从浮动到双倍。

     

从int,uint,long或ulong到float和from long或者的转换   ulong to double可能会导致精度损失,但永远不会导致   损失程度。其他隐式数字转换永远不会丢失   任何信息。

     

没有对char类型的隐式转换,所以。的值   其他整数类型不会自动转换为char类型。

因此,在程序和十进制之间进行转换时,C#知道它可以隐式地从任何数字类型转换为十进制,因此在执行此显式转换时,它将查找可以将程序转换为数字类型的任何运算符。

有趣的是,如果您还将显式转换为uint,那么会返回48会发生什么?编译器选择哪一个?

答案 1 :(得分:6)

我找到了答案。首先,有一种类型的概念被另一种包含,在 6.4.3评估用户定义的转换中定义如下:

  

如果存在从类型A到a的标准隐式转换(第6.3.1节)   类型B,如果A和B都不是接口类型,则说A   被包含在 B中,B被称为包含 A。

6.3.1标准隐式转换声明“隐式数字转换(第6.1.2节)”是标准隐式转换, 6.1.2隐式数字转换 turn定义了从longdecimal的隐式转换。因此,long 包含在 decimal中。

接下来, 6.4.5用户定义的显式转换指出确定显式转换是否适用的其中一个阶段是:

  

查找适用的用户定义和提升转换集   运算符,U。此集由用户定义和提升组成   类或语句声明的隐式或显式转换运算符   D中的结构转换自S包含或包含的类型   到T包含或包含的类型。如果U是空的,那么   转换未定义,发生编译时错误。

此处,D指的是较早步骤的结果,在这种情况下,仅包含decimalProgramobject。因此,集合U将包含我声明的Program - 到 - long显式运算符,因为long包含decimal(如前所述)。

接下来的步骤之一是选择long作为最具体的目标类型, TX

最后,同一算法的最后一步说明:

  

最后,应用转换:

     
      
  • 如果S不是SX,则执行从S到SX的标准显式转换。
  •   
  • 调用最具体的用户定义转换运算符以将SX转换为TX。
  •   
  • 如果TX不是T,则执行从TX到T的标准显式转换。
  •   

此处SSX都是Program,因此第一部分什么都不做。 TX被选为longT是目标类型decimal,因此最后一部分执行从long到{{1}的标准转换}。