在C#中追加字符串与char之间是否有任何惩罚

时间:2010-08-02 13:17:33

标签: c#

几年前在Java开发时,我了解到如果我有一个字符而不是一个字符串,最好附加一个字符,因为VM不需要对字符串值进行任何查找它的内部字符串池。

string stringappend = "Hello " + name + "."; 
string charappend = "Hello " + name + '.'; // better?

当我开始使用C#进行编程时,我从未想过它与“VM”相同的可能性。我遇到C# String Theory—String intern pool表示C#也有一个内部字符串池(我想如果它没有那么会很奇怪)所以我的问题是,

在连接到关于C#的字符串时是否有附加char而不是字符串的任何好处,还是仅仅是乱码?

编辑:请忽略StringBuilder和string.Format,我更感兴趣的是为什么我要替换“。”用'。'在代码中。我很清楚这些类和函数。

8 个答案:

答案 0 :(得分:16)

如果给出了选择,我会在调用string或(等效)char运算符时传递System.String.Concat而不是+

我在System.String.Concat看到的唯一重载都是字符串或对象。由于char不是字符串,因此将选择对象版本。这会导致char被装箱。在Concat验证对象引用不为null之后,它将在char上调用object.ToString。然后,在创建新的连续字符串之前,它将生成首先被避免的可怕的单字符字符串。

所以我不知道如何通过一个炭将获得任何收益。

也许有人想看看Reflector中的Concat操作,看看是否对char有特殊处理?

<强>更新

正如我所想,这个测试证实了char略慢。

using System;
using System.Diagnostics;

namespace ConsoleApplication19
{
    class Program
    {
        static void Main(string[] args)
        {
            TimeSpan throwAwayString = StringTest(100);
            TimeSpan throwAwayChar = CharTest(100);
            TimeSpan realStringTime = StringTest(10000000);
            TimeSpan realCharTime = CharTest(10000000);
            Console.WriteLine("string time: {0}", realStringTime);
            Console.WriteLine("char time: {0}", realCharTime);
            Console.ReadLine();
        }

        private static TimeSpan StringTest(int attemptCount)
        {
            Stopwatch sw = new Stopwatch();
            string concatResult = string.Empty;
            sw.Start();
            for (int counter = 0; counter < attemptCount; counter++)
                concatResult = counter.ToString() + ".";
            sw.Stop();
            return sw.Elapsed;
        }

        private static TimeSpan CharTest(int attemptCount)
        {
            Stopwatch sw = new Stopwatch();
            string concatResult = string.Empty;
            sw.Start();
            for (int counter = 0; counter < attemptCount; counter++)
                concatResult = counter.ToString() + '.';
            sw.Stop();
            return sw.Elapsed;
        }
    }
}

结果:

string time: 00:00:02.1878399
char time: 00:00:02.6671247

答案 1 :(得分:12)

  

几年前在Java开发时,我了解到如果我有一个字符而不是一个字符串,最好附加一个字符,因为VM不需要对字符串值进行任何查找它的内部字符串池。

char添加到String可能稍微比附加1个字符String更快,因为:

  • append(char)操作不必加载字符串length
  • 它不必加载对字符串characters数组的引用,
  • 它不必加载并添加字符串的start偏移量,
  • 它不必对数组索引和
  • 进行边界检查
  • 它不必递增并测试循环变量。

查看String及相关类的Java源代码。你可能会对引擎盖下的内容感到惊讶。

实习生游泳池与此无关。字符串文字的实习在类加载期间只发生一次 。仅当应用程序明确调用String.intern()时,才会实现非文字字符串的实习。

答案 2 :(得分:4)

这可能很有趣: http://www.codeproject.com/KB/cs/StringBuilder_vs_String.aspx

Stringbuilder不一定比Strings快,如前所述,依赖。这取决于机器配置,可用内存与处理器功率,框架版本和机器配置。在这种情况下,你的探查者是你最好的伙伴:)

返回2主题: 你应该试试哪个更快。做多次连接并让你的探查器观看。你会看到可能的差异。

答案 3 :(得分:3)

.NET中的所有字符串连接(使用标准运算符,即+)要求运行时为完整的新字符串保留足够的内存以保存连接的结果。这是由于字符串类型是不可变的。

如果您多次执行字符串连接(即在循环内等),您将遇到性能问题(如果字符串足够大,最终会出现内存问题),因为.NET运行时需要不断分配和释放内存空间保留每个新字符串。

这可能是因为你正在思考(正确地)过多的字符串连接可能会有问题。它与连接char而不是字符串类型相比很少(如果有的话)。

替代方法是在System.Text命名空间中使用StringBuilder类。此类表示一个可变的类似字符串的对象,可用于连接字符串而不会产生很多性能问题。这是因为StringBuilder类将为字符串保留特定数量的内存,并允许将连接附加到保留内存量的末尾,而不需要整个字符串的完整新副本。

修改

关于字符串查找与字符查找的细节,我掀起了这个小小的测试:

class Program
{
    static void Main(string[] args)
    {
        string stringtotal = "";
        string chartotal = "";
        Stopwatch stringconcat = new Stopwatch();
        Stopwatch charconcat = new Stopwatch();
        stringconcat.Start();
        for (int i = 0; i < 100000; i++)
        {
            stringtotal += ".";
        }
        stringconcat.Stop();
        charconcat.Start();
        for (int i = 0; i < 100000; i++)
        {
            chartotal += '.';
        }
        charconcat.Stop();
        Console.WriteLine("String: " + stringconcat.Elapsed.ToString());
        Console.WriteLine("Char  : " + charconcat.Elapsed.ToString());
        Console.ReadLine();
    }
}

它只是次数(使用高性能StopWatch类)连接类型字符串的100000个点/句点(.)与char类型的100000个点/句点所需的时间。 我运行了几次这个测试,以防止结果偏离一个特定的运行,但是,每次结果都类似于以下内容:

String: 00:00:06.4606331
Char  : 00:00:06.4528073

因此,在多个连接的上下文中,我会说在两者之间存在很小的差异(很可能,在考虑标准测试运行容差时没有差别)!

答案 4 :(得分:2)

我同意大家对使用StringBuilder的看法,如果你正在进行大量的字符串连接,因为String是一个不可变的类型,但是不要忘记创建StringBuilder类的开销也是如此,所以你必须做一个选择何时使用哪个。

在比尔瓦格纳的一本效果C#书中(或者可能是其中的三本书......),他也谈到了这一点。从广义上讲,如果您只需要将几个字符串片段添加到一起,则string.Format更好,但如果您需要在可能较大的循环中构建大字符串值,请使用StringBuilder。

答案 5 :(得分:0)

每次使用+运算符连接字符串时,运行时都会创建一个新字符串,为避免这种情况,建议的做法是使用具有Append方法的StringBuilder类。您还可以使用AppendLine和AppendFormat。 如果您不想使用StringBuilder,则可以使用string.Format:

string str = string.Format("Hello {0}.", name);

答案 6 :(得分:0)

由于字符串是不可变类型,因此在将值返回给您之前,都需要创建字符串的新实例。

我会考虑string.Concat(...)进行少量连接,或者使用StringBuilder类进行多次字符串连接。

答案 7 :(得分:0)

我无法与C#对话,但在Java中,主要优势不是编译时增益而是运行时增益。

是的,如果您使用String,那么在编译时Java必须在其内部池中查找String并可能创建一个新的String对象。但是这只会在编译时发生一次,当你创建.class文件时。用户永远不会看到这一点。

用户将看到的是,在运行时,如果你给一个角色,程序只需要检索角色。完成。如果给出一个String,它必须首先检索String对象句柄。然后它必须设置一个循环来遍历所有字符,检索一个字符,观察不再有字符,然后停止。我没有看过生成的字节码,但它显然是显着的工作时间。