【问题标题】:Why do I need an intermediate conversion to go from struct to decimal, but not struct to int?为什么我需要一个中间转换来从 struct 到 decimal,而不是 struct 到 int?
【发布时间】:2010-05-10 22:11:10
【问题描述】:

我有一个这样的结构,显式转换为浮点数:

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

我可以通过一次显式转换将 TwFix32 转换为 int:(int)fix32

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

没有从浮点到整数或十进制的隐式转换。为什么编译器让我在我要 int 时省略中间转换为 float,但在我要小数时却不允许?

【问题讨论】:

    标签: c# operators


    【解决方案1】:

    我常常不知所措,无法对“为什么”问题给出令人满意的答案。

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

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

    具体来说,相关段落是:

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

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

    我感觉这个答案并不令人满意。如果不是,你能改写这个问题,让它没有“为什么”这个词吗?我更擅长回答“什么”或“如何”的问题,而不是“为什么”的问题。

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

    【讨论】:

    • 我的感觉是,根本的问题是为什么(是的,我知道)从 int 到 float 的隐式转换应该会影响在相反方向发生的转换(TwFix32 到 float 到 int) .在我看来,这在这种情况下应该是一个无关紧要的转换——但显然不是,因为它会影响包容。我怀疑这里真正的“为什么”答案可能是,“因为它使许多其他案例按预期工作,但以这种奇怪为代价。”
    • @Jon:正确;如果您从分析 reference 类型上的用户定义转换的角度考虑这些规则,则更有意义;非接口引用类型通常没有浮点/十进制情况。
    猜你喜欢
    • 1970-01-01
    • 2012-01-15
    • 2021-02-26
    • 2014-01-06
    • 2014-10-20
    • 2017-03-31
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多