17

我很好奇将 double 转换为 int 的最佳方法。运行时安全是我在这里的主要关注点(它不一定是最快的方法,但这将是我的次要关注点)。我留下了一些我可以在下面提出的选项。任何人都可以权衡哪个是最佳实践吗?我没有列出任何更好的方法来实现这一点?

        double foo = 1;
        int bar;

        // Option 1
        bool parsed = Int32.TryParse(foo.ToString(), out bar);
        if (parsed)
        {
            //...
        }

        // Option 2
        bar = Convert.ToInt32(foo);

        // Option 3
        if (foo < Int32.MaxValue && foo > Int32.MinValue) { bar = (Int32)foo; }
4

8 回答 8

28

我认为您最好的选择是:

checked
{
    try
    {
        int bar = (int)foo;
    }
    catch (OverflowException)
    {
     ...          
    }
}

来自显式数字转换表

当您从 double 或 float 值转换为整数类型时,该值将被截断。如果生成的整数值超出目标值的范围,则结果取决于溢出检查上下文。在已检查的上下文中,会引发 OverflowException,而在未检查的上下文中,结果是目标类型的未指定值。

注意:选项 2在需要时也会抛出一个OverflowException

于 2010-08-23T15:51:29.977 回答
6

我更喜欢选项2。

您需要做的一件事是检查异常以确认它是否有效,就像您在选项 1 中检查“已解析”一样:

try
{
    bar = Convert.ToInt32(foo); 
}
catch(OverflowException)
{
    // no can do!
{

如果您要转换字符串等而不是双精度,则可能会得到一个“FormatException”。

编辑

我最初说选项 2 并不比选项 1 特别好,@0xA3 指出这是错误的。选项 1 更糟糕,因为它在解析为整数之前转换为字符串,这意味着它的效率较低。如果双精度超出整数范围(您可能想要也可能不想要),您也不会得到 OverflowException - 尽管在这种情况下 'parsed' 将为 False。

于 2010-08-23T15:53:05.550 回答
5

我意识到这并不是 OP 所要求的,但这些信息可能很方便。

这是一个比较(来自http://www.dotnetspider.com/resources/1812-Difference-among-Int-Parse-Convert-ToInt.aspx

        string s1 = "1234";
        string s2 = "1234.65";
        string s3 = null;
        string s4 = "12345678901234567890123456789012345678901234567890";

        int result;
        bool success;

        result = Int32.Parse(s1);      // 1234
        result = Int32.Parse(s2);      // FormatException
        result = Int32.Parse(s3);      // ArgumentNullException
        result = Int32.Parse(s4);      // OverflowException

        result = Convert.ToInt32(s1);      // 1234
        result = Convert.ToInt32(s2);      // FormatException
        result = Convert.ToInt32(s3);      // 0
        result = Convert.ToInt32(s4);      // OverflowException

        success = Int32.TryParse(s1, out result);      // 1234
        success = Int32.TryParse(s2, out result);      // 0
        success = Int32.TryParse(s3, out result);      // 0
        success = Int32.TryParse(s4, out result);      // 0
于 2010-08-23T15:58:49.937 回答
4

选项 3a 不使用异常,总是返回一个值:

    Int32 Convert(Double d)
    {
        if (d <= (double)Int32.MinValue)
            return Int32.MinValue;
        else if (d >= (double)Int32.MaxValue)
            return Int32.MaxValue;
        else 
            return (Int32)d;
    }
于 2010-08-23T16:08:07.753 回答
2

我会使用选项二。简短,干净并且有效。

您还可以查看 .Net4 中的 BigInteger 类,而不必检查溢出。

double foo = 1;            
BigInteger bigint = new BigInteger(foo);
于 2010-08-23T15:44:04.603 回答
2

我总是使用 Convert 类,我觉得它非常优雅、方便,您可以捕获 VS 智能感知中定义的特定异常。

于 2010-08-23T15:54:20.810 回答
1

选项 (1) 和 (2) 的作用基本相同。选项 (1) 为您提供一个if (parsed)块,而选项 (2) 对任何double不能表示为int.

选项 (3) 与选项 (2) 基本相同,只是它有一个额外的MinValue/MaxValue检查,而其他选项没有。

总之:这三段代码做不同的事情。选项 (3) 看起来是最稳健的,因为它有一个额外的范围检查。

编辑:再想一想,使用@Anichecked技巧-您可以免费获得范围检查。

于 2010-08-23T15:50:45.477 回答
1

如果您真的需要找出是否出了问题,请使用普通演员并检查结果。

int ToInt(double foo)
{
    int result = (int)foo;
    if (foo != result)
        throw new ArgumentException()

    return result;
}

这将确保没有进行无效转换。如果可以四舍五入到最接近的整数,请使用Math.Round并检查结果是否在 0.5 以内。这将确保您的方法不会得到 NaN 或无穷大。

于 2010-08-23T15:51:14.150 回答