C# 将对象转换为长对象

C# 将对象转换为长对象,c#,C#,我有以下功能: public virtual long AsLong(object originalValue,long defaultValue) { double buffer = defaultValue; if (originalValue != null) { double result; var readValueIsconverted = double.TryParse(

我有以下功能:

    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为负。那么问题出在哪里呢?

问题是,您试图在一个双精度
中保存一个包含19个有效数字(十进制)的整数值,而该双精度

因此,不可能在
double
中准确地表示值。显然,舍入会在转换为long时导致值溢出,使其成为负值

您可以这样确认:

var convertedValue = checked((long)roundedValue);

如果您一定要处理这种情况,我建议您使用double而不是double,或者在小数点处拆分字符串(或您的区域设置中使用的任何内容),并以这种方式处理舍入。

如果提供的参数在第一位是
long
,您应该检查:

public virtual long AsLong(object originalValue,long defaultValue)
{
    if(originalValue.GetType() == typeof(long))
        return (long) originalValue;

    double buffer = defaultValue;

    ...
}

否则,您可能会丢失有关
long
double
转换的一些信息。

检查
原始值的类型。它的编译时类型是
object
,但运行时的实际类型是什么?如果是盒式数字类型,则无需调用
.ToString()
后跟
TryParse
。最好直接取消装箱到正确的类型(特别是如果它始终是相同的运行时类型),然后在必要时转换为另一个数字类型

如果通过
double
发送包含许多数字的
long
,如
0x7FFFFFFFFFFFFFFF
,它与
long.MaxValue
相同,请注意
long
double
具有大约10位的精度。从技术上讲,这是因为双精度
使用11位作为指数,但不必存储最高有效位

当值为
long.MaxValue
时,
double
的精度会发生变化,因为当我们通过2的幂时,指数会上升1
double
值正好低于
long。MaxValue
的精度为1024。这意味着只能表示1024的整数倍。毫不奇怪,
double
值正好在
long.MaxValue
之上,其精度为2048。当然,整型
long
的精度总是正好为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
9.22337203685477'27'36 E+18
9.22337203685477'37'60东+18
9.22337203685477'47'84东+18
---

9.22337203685477'58'08 E+18为什么解析为double以返回long?请参见。。或者..因为可以将示例13.4作为参数传递。如果我对缓冲区使用了long,我就错过了这种可能性。long roundedValue=(long)Math.Round(myDoubleValue,0)@我不明白。我也做了同样的事情。不是吗?