为什么显式强制转换为' decimal '调用显式操作符' long ' ?

本文关键字:调用 操作符 long decimal 为什么 转换 | 更新日期: 2023-09-27 18:13:32

考虑以下代码:

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;换句话说,即使强制转换为decimal,也调用explicit operator long

c#规范中是否有明确指出应该发生这种情况(如果有,具体在哪里),或者这是我错过的其他规则的结果?

为什么显式强制转换为' decimal '调用显式操作符' long ' ?

我找到答案了。首先,存在一种类型被另一种类型包围的概念,该概念在6.4.3用户定义转换的求值中定义如下:

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

6.3.1标准隐式转换声明"隐式数字转换(§6.1.2)"是一个标准的隐式转换,而6.1.2隐式数字转换反过来定义了从longdecimal的隐式转换。因此,longdecimal包围。

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

查找适用的用户定义转换和提升转换的集合该集合由用户定义的和提升的组成类声明的隐式或显式转换操作符从包含或包含S的类型转换为D中的结构体转换为包含t或被t包围的类型转换未定义,发生编译时错误。

这里,D指的是前一步的结果,在这种情况下,只包含decimal, Programobject。因此,集合U将包含我声明的Programlong的显式运算符,因为long包含在decimal中(如前所述)。

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

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

最后,应用转换:
  • 如果S不是SX,则执行从S到SX的标准显式转换。
  • 调用最具体的用户自定义转换操作符,将SX转换为TX。
  • 如果TX不是T,则执行从TX到T的标准显式转换。

这里,SSX都是Program,所以第一部分什么都不做。选择TXlong, T为目标类型decimal,所以最后一部分执行从longdecimal的标准转换。

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

EDIT:数字类型之间的转换内置于语言规范中:

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、int、long、ulong、float、double或小数。

·从整型到长型、浮点型、双精度型或十进制。

·从int到long、ulong、float、double或decimal。

·从长型到浮点型、双精度型或十进制型

·从ulong到float、double或decimal。

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

·从float到double。

从int、int、long或ulong到float和从long or的转换二重运算可能会造成精度的损失,但绝不会造成一重运算量级损失。其他隐式数字转换永远不会丢失任何信息。

没有到char类型的隐式转换,因此其他整型不能自动转换为char类型。

因此,当在Program和decimal之间进行转换时,c#知道它可以隐式地从任何数字类型转换为decimal,因此在执行这种显式转换时,它将查找任何可以将Program转换为数字类型的操作符。

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