Double.TryParse 或 Convert.ToDouble - 哪个更快更安全?

Posted

技术标签:

【中文标题】Double.TryParse 或 Convert.ToDouble - 哪个更快更安全?【英文标题】:Double.TryParse or Convert.ToDouble - which is faster and safer? 【发布时间】:2010-10-09 20:13:51 【问题描述】:

我的应用程序使用 VSTO 读取 Excel 文件并将读取的数据添加到 StringDictionary。它只添加带有几位数字的数据(1000 1000,2 1000,34 - 逗号是俄罗斯标准中的分隔符)。

检查当前字符串是否为适当的数字更好?

object data, string key; // data had read

try

  Convert.ToDouble(regionData, CultureInfo.CurrentCulture);
  dic.Add(key, regionData.ToString());

catch (InvalidCastException)

  // is not a number

double d;
string str = data.ToString();
if (Double.TryParse(str, out d)) // if done, then is a number

  dic.Add(key, str);

由于以下解析算法问题,我必须使用StringDictionary 而不是Dictionary<string, double>

我的问题:哪种方式更快?哪个更安全?

打电话给Convert.ToDouble(object) 还是Convert.ToDouble(string) 更好?

【问题讨论】:

仅供参考,double.TryParse 与 try result = double.Parse(s); 相同。返回真; 捕捉 返回错误; 。 Convert 本质上是一个包含一堆重载的包装器。你怎么做没有区别。但正如 Jon 所指出的,请考虑如何处理错误的输入。 Double.TryParse 与包裹在 try..catch 中的 double.Parse 不同。语义相同,但代码路径不同。 TryParse 首先使用内部 Number.TryStringToNumber 验证字符串是否为数字,而 Parse 假定它已经是数字/双精度数。 【参考方案1】:

我在发布模式下做了一个非科学的快速测试。我在两种方法中都使用了两个输入:“2.34523”和“badinput”,并迭代了 1,000,000 次。

有效输入:

Double.TryParse = 646ms
Convert.ToDouble = 662 ms

没有太大的不同,正如预期的那样。对于所有意图和目的,对于有效输入,这些都是相同的。

输入无效:

Double.TryParse = 612ms
Convert.ToDouble = ..

嗯..它运行了很长时间。我使用 1,000 次迭代重新运行了整个过程,而输入错误的 Convert.ToDouble 花了 8.3 秒。平均下来,需要2个多小时。我不在乎测试有多基础,在无效输入的情况下,Convert.ToDouble 的异常引发会毁了你的表现。

所以,这是TryParse 的另一票,并附有一些数字来支持它。

【讨论】:

除了上面提到的这些,我刚刚发现Convert.ToDouble()会抛出一个带有科学计数法数字的异常。考虑一下: double toDouble = Convert.ToDouble((-1/30000).ToString()); // 将失败 double dblParse = Double.Parse((-1/30000).ToString()); // 工作正常【参考方案2】:

首先,我会使用double.Parse 而不是Convert.ToDouble

至于你应该使用Parse还是TryParse:如果输入数据错误,你能继续吗,或者这是一个非常特殊的情况?如果异常,请使用Parse,如果输入错误则让它炸毁。如果这是预期的并且可以干净地处理,请使用TryParse

【讨论】:

乔恩,您能否详细说明为什么您更喜欢 double.Parse 而不是 Convert.ToDouble? @dnorthut:基本上,我很少希望将 null 转换为 0(Convert.ToDouble 就是这样做的)。它通常也更灵活。我只是倾向于使用特定的方法......【参考方案3】:

.NET Framework 设计指南建议使用 Try 方法。避免异常通常是个好主意。

Convert.ToDouble(object) 会做((IConvertible) object).ToDouble(null);

哪个会调用Convert.ToDouble(string, null)

所以调用字符串版本会更快。

但是,字符串版本只是这样做:

if (value == null)

    return 0.0;

return double.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider);

所以直接使用double.Parse 会更快。

【讨论】:

【参考方案4】:

如果您不打算处理异常,请使用 TryParse。 TryParse 更快,因为它不必处理整个异常堆栈跟踪。

【讨论】:

【参考方案5】:

我通常会尽量避免使用 Convert 类(意思是:我不使用它),因为我觉得它非常令人困惑:由于 Convert 允许大量语义使用相同的代码会发生非常不同的转换。这使得程序员很难控制到底发生了什么。

因此,我的建议是永远不要使用这个类。这也不是必需的(除了数字的二进制格式,因为数字类的普通 ToString 方法没有提供适当的方法来执行此操作)。

【讨论】:

【参考方案6】:

除非您 100% 确定您的输入(这种情况很少发生),否则您应该使用 Double.TryParse。

Convert.ToDouble will throw an exception on non-numbers
Double.Parse will throw an exception on non-numbers or null
Double.TryParse will return false or 0 on any of the above without generating an exception.

当你抛出异常时,解析的速度就变得次要了,因为没有比异常慢多少。

【讨论】:

【参考方案7】:

这里的 Convert 类很多人讨厌...只是为了平衡一点,Convert 有一个优势 - 如果你拿到一个对象,

Convert.ToDouble(o);

如果 o 已经是 Double (或 int 或任何易于转换的对象),则可以轻松返回值。

如果您已经将 Double.Parse 或 Double.TryParse 放在字符串中,那么使用它会很棒,但是

Double.Parse(o.ToString());

必须先制作要解析的字符串,这取决于您的输入,这可能会更昂贵。

【讨论】:

+1:我明白你的观点,在 System.Object 中用数字解析盒装数字/字符串非常容易,而不是大量的类型检查。但基本上我同意其他答案:Convert.ToSomething() 比 Parse/TryParse 贵得多,尤其是在迭代上下文中 对我来说,Convert.ToDouble(o) 有一些简单的出局,如果盒子里的东西已经是一个数字,但 Convert 的真正杀手是它没有 .TryToDouble(o , 出 d);考虑到异常的昂贵程度(以及您对输入的信心(或不相信)),这是 Convert 的一大笔额外费用。【参考方案8】:

Double.TryParse IMO。

你更容易处理,你会知道错误发生在哪里。

然后,如果它返回 false(即无法转换),您可以按照您认为合适的方式处理它。

【讨论】:

【参考方案9】:

我一直更喜欢使用TryParse() 方法,因为它会吐出转换成功或失败,而不必担心异常。

【讨论】:

【参考方案10】:

这是一个有趣的老问题。我正在添加一个答案,因为没有人注意到原始问题的一些内容。

哪个更快:Convert.ToDouble 还是 Double.TryParse? 哪个更安全:Convert.ToDouble 还是 Double.TryParse?

我将详细回答这两个问题(稍后我会更新答案),但首先:

为了安全起见,每个程序员在这个问题中错过的事情是这行(强调我的):

它只添加带有几位数字的数据(1000 1000,2 1000,34 - 逗号是俄罗斯标准中的分隔符)。

后面是这个代码示例:

Convert.ToDouble(regionData, CultureInfo.CurrentCulture);

这里有趣的是,如果电子表格是俄罗斯数字格式,但 Excel 没有正确键入单元格字段,那么对来自 Excel 的值的正确解释是什么?

关于速度,这两个例子还有一个有趣的地方:

catch (InvalidCastException)

    // is not a number

这可能会生成如下所示的 MSIL:

catch [mscorlib]System.InvalidCastException 

  IL_0023:  stloc.0
  IL_0024:  nop
  IL_0025:  ldloc.0
  IL_0026:  nop
  IL_002b:  nop
  IL_002c:  nop
  IL_002d:  leave.s    IL_002f
  // end handler
IL_002f: nop
IL_0030: return

从这个意义上说,我们可能可以比较每个程序执行的 MSIL 指令总数 - 稍后我会更新这篇文章。

我认为代码应该是正确、清晰和快速的……按这个顺序!

【讨论】:

【参考方案11】:

就我个人而言,我发现TryParse 方法更易于阅读,您实际想要使用的方法取决于您的用例:如果错误可以在本地处理,您预计会出现错误,TryParse 的 bool 是很好,否则您可能只想让异常发生。

我希望TryParse 也更快,因为它避免了异常处理的开销。但是使用基准工具,例如Jon Skeet's MiniBench 来比较各种可能性。

【讨论】:

对此答案的反馈:如果问题询问什么更快、更安全,则答案不应以“个人”开头,并包括诸如“我希望...”之类的猜测。这只是个人想法和评论,不是一个好的答案。

以上是关于Double.TryParse 或 Convert.ToDouble - 哪个更快更安全?的主要内容,如果未能解决你的问题,请参考以下文章

无法让 double.TryParse 在 Linq 表达式树中工作

TryParse 适用于 var 但不适用于 C# 中的对象?

属性或索引器不能作为 out 或 ref 参数传递

TryCast 加倍?

asp.net 怎么让用户在文本框里填入的是数字和带有小数点? 正则也行!

莫名奇妙的异常008:C#中多位小数问题