Why is double implicitly converted to int in a cast operator?

huangapple go评论73阅读模式
英文:

Why is double implicitly converted to int in a cast operator?

问题

这是我以前没有注意到的奇怪行为。我预期不能从double进行强制转换,但实际上double值会被隐式转换为int,而且我会无声地丢失小数部分。难道我真的不能从int进行转换而不转换为double吗?

readonly struct TestDecimal {
   public decimal Value { get; }

   TestDecimal(decimal value) => 
      Value = value;

   public static explicit operator TestDecimal(int x) => new(x);
}

...

// 这些断言失败了,但实际上这甚至不应该编译通过
[TestMethod]
public void Test_CastFromDouble() {
   var value = (TestDecimal)12.34; // 不应该编译通过
   Assert.AreEqual(12.34m, value.Value); // 断言失败,实际值:12.0m
}

[TestMethod]
public void Test_CastFromDecimal() {
   var value = (TestDecimal)12.34m; // 不应该编译通过
   Assert.AreEqual(12.34m, value.Value); // 断言失败,实际值:12.0m
}
英文:

This is strange behaviour that I haven't noticed before. I expected not to be able to cast from a double but instead the double value is implicitly converted to an int and I silently lose the fractional portion. Can I really not convert from ints without also converting from doubles?

readonly struct TestDecimal {
   public decimal Value { get; }

   TestDecimal(decimal value) => 
      Value = value;

   public static explicit operator TestDecimal(int x) => new(x);
}

...

// these assertions fail, but really this shouldn't even compile
[TestMethod]
public void Test_CastFromDouble() {
   var value = (TestDecimal)12.34; // shouldn't compile
   Assert.AreEqual(12.34m, value.Value); // assertion failed, actual value: 12.0m
}

[TestMethod]
public void Test_CastFromDecimal() {
   var value = (TestDecimal)12.34m; // shouldn't compile
   Assert.AreEqual(12.34m, value.Value); // assertion failed, actual value: 12.0m
}

答案1

得分: 2

这是因为**标准转换**可以作为用户定义的转换的一部分发生。在您的用户定义的转换之前,可以有一个标准转换,将表达式的类型转换为您的转换运算符所期望的类型。还可以有另一个标准转换,将您的转换运算符的返回值转换为在该上下文中期望的任何类型。

§10.5.3 用户定义的转换的评估

一旦确定了最特定的用户定义的转换运算符,用户定义的转换的实际执行涉及最多三个步骤:

  • 首先,如果需要,从源表达式到用户定义的或提升的转换运算符的操作数类型执行标准转换。
  • 接下来,调用用户定义的或提升的转换运算符来执行转换。
  • 最后,如果需要,从用户定义的转换运算符的结果类型到目标类型执行标准转换。

然后,本节继续定义了诸如最广泛的类型之类的术语,然后在§10.5.5中描述了这些转换是如何解决的。

对于您的情况最重要的是,标准显式转换包括"从doubleint"和"从decimalint"。这使您能够使用double/decimal作为参数调用您的转换运算符。请参阅语言规范的以下部分:

§10.4.3:

标准显式转换是所有标准隐式转换以及具有相反标准隐式转换的显式转换的子集。

"从doubleint"和"从decimalint"都是"具有相反标准隐式转换的显式转换"。

§10.3.2 显式数值转换:

  • ...
  • doublesbytebyteshortushortintuintlongulongcharfloatdouble
  • decimalsbytebyteshortushortintuintlongulongcharfloatdouble
  • ...

§10.4.2

以下隐式转换被分类为标准隐式转换:

  • ...
  • 隐式数值转换(§10.2.3)

§10.2.3:

隐式数值转换包括:

  • ...
  • intlongfloatdoubledecimal
  • ...
英文:

This is because standard conversions can occur as part of a user-defined conversion. Before your user-defined conversion, there can be a standard conversion converting the expression's type to the type your conversion operator expects. There can also be another standard conversion converting the return value of your conversion operator to whatever type is expected in that context.

§10.5.3 Evaluation of user-defined conversions

> Once a most-specific user-defined conversion operator has been
> identified, the actual execution of the user-defined conversion
> involves up to three steps:
>
> - First, if required, performing a standard conversion from the source expression to the operand type of the user-defined or lifted
> conversion operator.
> - Next, invoking the user-defined or lifted conversion operator to perform the conversion.
> - Finally, if required, performing a standard conversion from the result type of the user-defined conversion operator to the target
> type.

This section then goes on to define terms such as most-encompassing type, which are then used in §10.5.5 to describe how exactly these conversions are resolved.

Most importantly for your case, the standard explicit conversions include "double to int" and "decimal to int". This enables you to call your conversion operator with double/decimal as arguments. See the language spec sections:

§10.4.3:

> The standard explicit conversions are all standard implicit
> conversions plus the subset of the explicit conversions for which an
> opposite standard implicit conversion exists.

Both "double to int" and "decimal to int" are "explicit conversions for which an opposite standard implicit conversion exists".

§10.3.2 Explicit numeric conversions:

> - ...
> - From double to sbyte, byte, short, ushort, int, uint, long, ulong, char, float, or double.
> - From decimal to sbyte, byte, short, ushort, int, uint, long, ulong, char, float, or double.
> - ...

§10.4.2

> The following implicit conversions are classified as standard implicit
> conversions:
>
> - ...
> - Implicit numeric conversions (§10.2.3)

§10.2.3:

> The implicit numeric conversions are:
>
> - ...
> - From int to long, float, double, or decimal.
> - ...

huangapple
  • 本文由 发表于 2023年7月17日 10:19:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76701166.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定