正在将对象转换为长
本文关键字:转换 对象 | 更新日期: 2023-09-27 18:00:35
我有以下功能:
public virtual long AsLong(object originalValue,long defaultValue)
{
double buffer = defaultValue;
if (originalValue != null)
{
double result;
var readValueIsconverted = double.TryParse(originalValue.ToString(), out result);
if (readValueIsconverted)
buffer = result;
}
var roundedValue = Math.Round(buffer, 0);
var convertedValue = (long) roundedValue;
return convertedValue;
}
我使用了double,以便允许14.4的转换!我有以下失败的测试:
[Fact]
public void CanConvertLongMaxValue()
{
var cellValue = new Converter();
const long longValue = 0x7FFFFFFFFFFFFFFF;
var result = cellValue.AsLong(longValue, 12);
Assert.Equal(longValue, result);
}
我已经跟踪了代码,roundedValue为正,但convertedValue为负。那么问题出在哪里呢?
问题是您试图在具有15-16个有效数字的double
中保存一个具有19个有效数字(十进制)的整数值。
因此,不可能在double
中准确地表示该值。显然,四舍五入会导致值在转换为长值时溢出,从而使其成为负值。
你可以这样确认:
var convertedValue = checked((long)roundedValue);
如果您绝对必须处理这种情况,我建议使用decimal
而不是双精度,或者将字符串拆分到小数点(或您所在区域中使用的任何字符串),并以这种方式处理舍入。
检查originalValue
的类型。它的编译时类型是object
,但在运行时真正的类型是什么?如果是盒装号码类型,则不需要调用.ToString()
然后再调用TryParse
。最好直接取消装箱为正确的类型(尤其是如果它总是相同的运行时类型),然后在必要时转换为另一个数字类型。
如果您通过double
发送具有多个数字的long
,如与long.MaxValue
相同的0x7FFFFFFFFFFFFFFF
,请注意,long
的精度比double
高大约10位。从技术上讲,这是因为double
使用11位作为指数,但不必存储最高有效位。
在值为long.MaxValue
时,double
的精度会发生变化,因为当我们通过2的幂时,指数会上升1。刚好低于CCD_ 18的CCD_ 17值具有1024的精度。这意味着只能表示1024的整数倍。毫不奇怪,仅高于long.MaxValue
的double
值的精度为2048。当然,整数类型CCD_ 21的精度总是恰好为1。
以下是三个最接近的double
下方和三个最靠近的long.MaxValue
上方:
9.22337203685477'27'36 E+18
9.22337203685477'37'60 E+18
9.22337203685477'47'84 E+18
---
9.22337203685477'58'08 E+18 <-- two to the 63rd power
9.22337203685477'78'56 E+18
9.22337203685477'99'04 E+18
当您将long.MaxValue
(即9223372036854775807
)转换为double
时,最接近的表示是9.223372036854775808E+18
,这是1.0
过大。它用.ToString()
表示的字符串将只显示15位数字,而.ToString("R")
将显示17位数字(我上面列表中的撇号'
)。当将double
`9.223372036854775808E+18
转换回long
时,由于数字1.0
太大,我们得到溢出异常。当然,您仍然可以将数字转换为ulong
,这将显示确切的值。
如果提供的参数第一位是long
,您应该检查:
public virtual long AsLong(object originalValue,long defaultValue)
{
if(originalValue.GetType() == typeof(long))
return (long) originalValue;
double buffer = defaultValue;
...
}
否则,您可能会丢失long
到double
转换的一些信息。