为什么我需要一个中间转换从struct到decimal,而不是struct到int?

Jes*_*rew 8 c# operators

我有这样的结构,显式转换为float:

struct TwFix32
{
    public static explicit operator float(TwFix32 x) { ... }
}
Run Code Online (Sandbox Code Playgroud)

我可以使用一个显式转换将TwFix32转换为int: (int)fix32

但要将其转换为十进制,我必须使用两个强制转换: (decimal)(float)fix32

没有从float到int或decimal的隐式转换.为什么编译器让我在进入int时省略了浮动的中间转换,但是当我要去小数时呢?

Eri*_*ert 8

我常常无法对"为什么"的问题给出满意的答案.

C#编译器表现出这种行为的原因是因为它(在这种情况下至少是(*))是C#规范的正确实现.

规范的第6.4.5节描述了如何分析用户定义的转换.仔细阅读该部分将解释为什么显式转换为int是合法的,但对于decimal则不然.

具体而言,相关段落是:

查找适用的用户定义和提升转换运算符集合U.此集合包含由D中的类或结构声明的用户定义和提升的隐式或显式转换运算符,这些运算符从包含或包含在S中的类型转换为T包含或包含T.如果U为空,则转换未定义,并发生编译时错误.

在您的情况下,S是TwFix,T是int或decimal.TwFix上唯一的用户定义的显式转换返回一个浮点数.int包含在float中,但decimal既不包含也不包含float.因此,组U在一种情况下具有成员而在另一种情况下是空的.因此,一个案例会产生错误,正如规范所说的那样,而另一个则没有.

我觉得这个答案并不令人满意.如果没有,你能否重新解释这个问题,使其中没有"为什么"这个词?我在回答"什么"或"如何"问题而不是"为什么"问题方面要好得多.

(*)编译器已知代码中的错误,这些错误计算一种类型是否包含另一种类型,以便在分析特定用户定义转换的语义时确定哪些内置转换是相关的.在许多情况下,我们故意不修复这些错误,因为这样做会在现实世界的代码中引入一个重大变化,没有太大的好处.我非常希望重新审视规范的这一部分并重写它,以便删除"包含类型"的概念; 这个规格有点奇怪.并且,正如您所发现的,它产生了这种奇怪性,其中float可显式转换为十进制,十进制可显式转换为float,但由于两者都不包含另一个,因此用户定义的显式转换代码不喜欢它.然而,这是非常低的优先级.