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

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

struct TwFix32 { public static explicit operator float(TwFix32 x) { ... } } 

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

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

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

我常常无法对“为什么”的问题给出满意的答案。

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

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

具体而言,相关段落是:

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

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

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

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