英文:
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 int
s without also converting from double
s?
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.5中描述了这些转换是如何解决的。
对于您的情况最重要的是,标准显式转换包括"从double
到int
"和"从decimal
到int
"。这使您能够使用double
/decimal
作为参数调用您的转换运算符。请参阅语言规范的以下部分:
标准显式转换是所有标准隐式转换以及具有相反标准隐式转换的显式转换的子集。
"从double
到int
"和"从decimal
到int
"都是"具有相反标准隐式转换的显式转换"。
- ...
- 从
double
到sbyte
、byte
、short
、ushort
、int
、uint
、long
、ulong
、char
、float
或double
。- 从
decimal
到sbyte
、byte
、short
、ushort
、int
、uint
、long
、ulong
、char
、float
或double
。- ...
以下隐式转换被分类为标准隐式转换:
- ...
- 隐式数值转换(§10.2.3)
隐式数值转换包括:
- ...
- 从
int
到long
、float
、double
或decimal
。- ...
英文:
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:
> 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
.
> - ...
> The following implicit conversions are classified as standard implicit
> conversions:
>
> - ...
> - Implicit numeric conversions (§10.2.3)
> The implicit numeric conversions are:
>
> - ...
> - From int
to long
, float
, double
, or decimal
.
> - ...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论