如何进一步优化此代码?

时间:2010-04-15 22:36:10

标签: c# optimization

请查看以下代码:

StringBuilder row = TemplateManager.GetRow("xyz"); // no control over this method 
StringBuilder rows = new StringBuilder();

foreach(Record r in records)
{
    StringBuilder thisRow = new StringBuilder(row.ToString());
    thisRow.Replace("%firstName%", r.FirstName)
       .Replace("%lastName%", r.LastName)
          // all other replacement goes here
       .Replace("%LastModifiedDate%", r.LastModifiedDate);

    //finally append row to rows
    rows.Append(thisRow);
}

目前3个StringBuilders和 row.ToString()位于循环内。这里有进一步优化的空间吗?

9 个答案:

答案 0 :(得分:12)

这是您申请中的瓶颈吗?你有没有对它进行分析并知道它需要优化?

除非您需要,否则请勿进行优化。预先成熟的优化会导致可维护的代码更少,甚至可能无法优化。

答案 1 :(得分:8)

我认为用字符串替换thisRow可能会更快,但我做了一些测试并且StringBuilder赢了。

String.Replace()创建一个新字符串,价格昂贵。 StringBuilder.Replace()修改其缓冲区中的字符串,这比较便宜。在我的测试中,我使用了一串500个字符并执行了6 Replace()个。 StringBuilder的速度提高了约5%,包括每次迭代创建一个新的。

但是,您应该做的一件事是将row.ToString()移到循环之外。为每条记录调用它是通过创建一个新字符串来浪费周期。

String row = TemplateManager.GetRow("xyz").ToString();
StringBuilder rows = new StringBuilder(); 

foreach(Record r in records) 
{ 
    StringBuilder thisRow = new StringBuilder(row);  
    thisRow.Replace("%firstName%", r.FirstName) 
                   .Replace("%lastName%", r.LastName) 
                   .Replace("%LastModifiedDate%", r.LastModifiedDate); 
    rows.Append(thisRow);
}    

答案 2 :(得分:5)

你可以将row.ToString()带出循环; row永远不会在循环内部发生变化。

答案 3 :(得分:2)

我认为row应该是string,而不是StringBuilder。 更多的设计评论而不是优化。

答案 4 :(得分:2)

StringBuilders通常只在将字符串连接成非常大的字符串时提供很大的改进,而不是非常大量的字符串。如果您的行很小,您可以考虑使用正常字符串计算此代码。

string row = TemplateManager.GetRow("xyz").ToString();
foreach (Record r in records) 
    rows.Append(row
        .Replace("%firstName%", r.FirstName)
        .Replace("%lastName", r.LastName)
        // ....
        );

或者只使用XSLT

答案 5 :(得分:1)

如果行很小,那么没什么大不了的,但你可以尝试将这三个替换组合成一个替换动作。

修改:您可以使用循环遍历StringBuilder中的每个字符来完成此操作。由于您似乎正在基于%name%进行替换,因此您可以走路直到看到%并捕获文本,直到遇到另一个%。如果捕获的文本与您的替换keys匹配,请替换其替换值并忽略该文本,直到您遇到下一个%并重复捕获过程。否则,请考虑从您遇到的最后%处尝试捕获过程。这大致是你想要做的。当然,任何与键不匹配的文本都必须附加到输出StringBuilder

答案 6 :(得分:0)

StringBuilder row = TemplateManager.GetRow("xyz"); // no control over this method 
StringBuilder rows = new StringBuilder();

foreach(Record r in records)
{
    row.Replace("%firstName%", r.FirstName)
       .Replace("%lastName%", r.LastName)
          // all other replacement goes here
       .Replace("%LastModifiedDate%", r.LastModifiedDate);

    //finally append row to rows
    rows.Append(row);
}

答案 7 :(得分:0)

根据“记录”是什么以及有多少,您可能会考虑使用for而不是foreach。

我发现Jon Skeet的benchmarking analysis of for vs foreach很有趣。

答案 8 :(得分:0)

像Ben说的那样,不要这样做!

但是如果必须的话,显而易见的优化是移动所有索引的计算以便在哪里复制以及完全替换循环的位置。 'rows'是常量,因此其中每个可替换参数的位置是不变的。

如果你这样做,循环变成了一堆SubString()和连接操作,它的运行速度提高了约3倍,模板中只有一个按顺序运行。

或者,对于一个更容易(但仍然有问题)的优化,可以轻松处理重复(但不是模板字符串中的{#}值!)...

string format = row.Replace("%firstname%,"{0}").Replace("%...

for ...

   string thisRow = string.format(format, r.FirstName, r.LastName, r.LastModifiedDate);

   ...