考虑以下代码:
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#规范中有没有明确说明应该发生这种情况(如果是,具体发生在哪里),或者这是我遗漏的其他规则的结果吗?
发布于 2011-11-02 22:52:27
我找到了答案。首先,存在一种类型被另一种类型包含的的概念,这在6.4.3用户定义的转换评估中定义如下:
如果存在从类型A到类型B的标准隐式转换(§6.3.1),并且如果A和B都不是接口类型,则A称为B包含的,B称为包含A。
6.3.1标准隐式转换说明“隐式数值转换(§6.1.2 )”是标准隐式转换,6.1.2隐式数值转换又定义了从long
到decimal
的隐式转换。因此,long
是由 decimal
包含的。
接下来,6.4.5用户定义的显式转换指出,确定显式转换是否适用的阶段之一是:
查找适用的用户定义和提升的转换运算符U的集合。该集合由D中的类或结构声明的用户定义和提升的隐式或显式转换运算符组成,D中的类或结构将包含或包含在S中的类型转换为包含或包含在T中的类型。如果U为空,则转换是未定义的,并且会发生编译时错误。
这里,D
指的是前一步的结果,在本例中,该步骤只包含decimal
、Program
和object
。因此,集合U
将包含我声明的Program
-to-long
显式运算符,因为long
包含在decimal
中(正如我们前面所发现的)。
下一步之一是选择long
作为最具体的目标类型TX
。
最后,该算法的最后一步是:
最后,应用转换:
这里,S
和SX
都是Program
,所以第一部分什么也不做。TX
被选为long
,T
是目标类型decimal
,因此最后一部分执行从long
到decimal
的标准转换。
发布于 2011-11-02 22:33:40
我能想到的唯一解释是,编译器足够聪明,意识到有一个隐式运算符可以将long转换为decimal,当Program只能转换为long时,它可以用来满足Program和decimal之间的显式转换。
EDIT:在这里;数字类型之间的转换内置于语言规范中:
6.1.2隐式数字转换
隐式数字转换为:
·从sbyte到short、int、long、float、double或decimal。
·从字节到短、ushort、int、uint、long、ulong、float、double或decimal。
·从短整型到整型、长整型、浮点型、双精度或小数型。
·从ushort到int、uint、long、ulong、float、double或decimal。
·从整型到长整型、浮点型、双精度或小数型。
·从uint到long、ulong、float、double或decimal。
·从长整型到浮点型、双精度型或小数型。
·从ulong到float、double或decimal。
·从char到ushort、int、uint、long、ulong、float、double或decimal。
·从浮动到双倍。
从int、uint、long或ulong到float以及从long或ulong到double的转换可能会导致精度损失,但永远不会导致幅度损失。其他隐式数值转换不会丢失任何信息。
不存在到char类型的隐式转换,因此其他整数类型的值不会自动转换为char类型。
因此,当在Program和decimal之间进行转换时,C#知道它可以隐式地从任何数值类型转换为decimal,所以当执行这种显式转换时,它将查找可以将Program转换为数值类型的任何运算符。
有趣的是,如果你也显式地转换到uint,返回48,会发生什么?编译器会选择哪一个?
https://stackoverflow.com/questions/7982014
复制相似问题