将对象转换为双倍的最快方法?

时间:2010-07-02 16:04:06

标签: c# performance .net-3.5

将对象转换为double的最快方法是什么?我现在正处于一段代码中,其中包括:

var d = double.TryParse(o.ToString(), out d);  // o is the Object...

首先想到的是将其重写为

var d = Convert.ToDouble(o);

但实际上会更快吗?

编辑:除了运行配置文件(顺便说一句,我强烈建议 JetBrains dotTrace 给任何开发人员),我运行了Reflector,这帮我来了以下内容(或多或少代码的相关部分):

if (o is IConvertible)
{
    d = ((IConvertible)o).ToDouble(null);
}
else
{
    d = 0d;
}

原始代码double.TryParse()在140毫秒内执行。新代码在34ms内执行。我几乎可以肯定这是我应该采取的优化路径,但在我这样做之前,有没有人看到我的“优化”代码出现问题?提前感谢您的反馈!

5 个答案:

答案 0 :(得分:14)

你必须做很多这些事情,以便在任何时候花在这上面。但是,我不是来判断:

所以,你的代码是这样的:

if (o is IConvertible)
{
    d = ((IConvertible)o).ToDouble(null);
}
else
{
    d = 0d;
}

我想知道你是否会更好地使用这个

IConvertible convert = o as IConvertible;

if (convert != null)
{
  d = convert.ToDouble(null);
}
else
{
  d = 0d;
}

为您节省双重演员。

答案 1 :(得分:6)

我尝试了以下方法。

  • double.TryParse
  • double.Parse
  • Convert.ToDouble

我使用了以下代码。

public static void Main()
{
    string text = "3.14";
    var timer = new Stopwatch();
    timer.Start();
    for (int i = 0; i < 10000000; i++)
    {
        double d;
        d = Convert.ToDouble(text);
        //double.TryParse(text, out d);
        //d = double.Parse(text);
    }
    timer.Stop();
    Console.WriteLine("Time=" + timer.Elapsed.ToString());
    Console.ReadLine();
}

在我的机器上,我看到了这些结果。我平均进行了3次不同的跑步。

  • double.TryParse = 4.45秒
  • double.Parse = 4.45秒
  • Convert.ToDouble = 4.75秒

当然,我使用了可转换的字符串。如果字符串不可转换,那么我非常怀疑double.TryParse将是最快的一次。

答案 2 :(得分:3)

使用System.Diagnostics.Stopwatch创建一个小型测试应用程序,看看哪个更快。虽然我认为这不会产生有价值的差异。纯粹是为了可读性,我会去Convert.ToDouble

答案 3 :(得分:1)

首先,如果您真的想知道哪个更快,您应该编写一个快速测试(使用您希望处理的数据)并为每个选项计时。在不知道o是什么(或可能是什么)的情况下,很难判断。我怀疑你不会发现太大的不同。

其次,除非你在代码的时间关键部分调用这段代码,并且称它有数千次启动时间,否则我怀疑它真的很重要。写好,干净的代码,然后优化。

答案 4 :(得分:0)

你可能会尝试做几件不同的事情,这取决于o是什么类型的东西。它可能是

a)盒装双,你只想取消装箱:

object o = 53.2;
double d = (double)o;

b)其他类型,值或引用,有一些转换为可用的双重(实现IConvertible.ToDouble())你想要使用

object o = 53.2M; // a System.Decimal
double d = Convert.ToDouble(o);

c)具有默认字符串表示形式的东西,可以解析为双重

object o = "53.2";
double d;
bool convertedOK = double.TryParse(o.ToString(), out d);

在某种意义上,选项c是最长的回合方式;你正在取你的对象,要求它的字符串表示,然后尝试解析该字符串以获得双精度。如果你不需要这样做,这很笨拙,而在你的40,000个电话的例子中,它将创建和丢弃40,000个字符串......

如果您知道您的对象将始终包含实现转换为double的内容,则可以跳过所有内容并转到选项b。如果您知道您的对象只是一个盒装双,请选择最简单的选项(a)将其取消装箱。

如果你真的不知道将会是什么,也许这些方面的东西对你有用吗?

double d = (o is double) ? (double)o
    : (o is IConvertible) ? (o as IConvertible).ToDouble(null)
    : double.Parse(o.ToString());

(注意:如果o包含实现IConvertible但不能转换为double的内容,或者如果其字符串表示不能被解析为double,则无法工作

我还没有说过有关相对速度的任何内容,但如果取消装箱并不比转换为字符串然后进行解析(除非优化器非常聪明),我会感到惊讶。

使用.NET秒表在LINQPad中进行快速测试表明存在很大差异。

IEnumerable<object> myData = new List<object>() { "53.2", 53.2M, 53.2D };
const int iterations = 10000000;
var sw = new Stopwatch();
var results = new List<string>();

foreach (var o in myData)
{
    sw.Reset();
    sw.Start();

    for (var i=0; i < iterations; i++)
    {
        double d = (o is double) ? (double)o
            : (o is IConvertible) ? (o as IConvertible).ToDouble(null)
            : double.Parse(o.ToString());
    }

    sw.Stop();

    results.Add($"{o.GetType()}: {iterations} iterations took {sw.ElapsedMilliseconds}ms");
}

results.Dump();
我的电脑上的

给出了以下结果

System.String: 10000000 iterations took 1329ms 
System.Decimal: 10000000 iterations took 402ms 
System.Double: 10000000 iterations took 38ms