C# 谁是短字符串拼接之王 目录.Net测试代码测试结果结论Unity测试代码测试结果结论在开发过程中我们经常会遇到短字符串拼接的情况例如需要打印状态信息进度信息“20/100”等那么多的拼接方法哪个又好又快呢。今天写了一个benchmark看一下。.Net测试代码usingSystem.Text;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Jobs;usingLinkDotNet.StringBuilder;publicenumTestState{Idle,Running,Jumping}[MemoryDiagnoser][SimpleJob(RuntimeMoniker.Net80)]publicclassIntToStringBenchmark{privatereadonlyTestState_valueTestState.Idle;privatereadonlyint_maxValue100;[Benchmark(Baselinetrue)]publicstringIntToString(){varval${_value.ToString()}/{_maxValue.ToString()};returnval;}[Benchmark]publicstringIntInterpolation(){varval${_value}/{_maxValue};returnval;}[Benchmark]publicstringIntStringBuilder(){varstringBuildernewStringBuilder();stringBuilder.Append(_value);stringBuilder.Append(/);stringBuilder.Append(_maxValue);returnstringBuilder.ToString();}[Benchmark]publicstringIntValueStringBuilder(){usingValueStringBuilderstringBuildernew();stringBuilder.Append(_value);stringBuilder.Append(/);stringBuilder.Append(_maxValue);returnstringBuilder.ToString();}[Benchmark]publicstringIntValueStringBuilderstackalloc(){usingValueStringBuilderstringBuildernew(stackallocchar[8]);stringBuilder.Append(_value.ToString());stringBuilder.Append(/);stringBuilder.Append(_maxValue);returnstringBuilder.ToString();}}测试结果MethodMeanErrorStdDevRatioRatioSDGen0AllocatedAlloc RatioIntToString23.84 ns0.391 ns0.365 ns1.000.000.010264 B1.00IntInterpolation42.59 ns0.485 ns0.453 ns1.790.030.006340 B0.62IntStringBuilder35.15 ns0.344 ns0.305 ns1.480.030.0268168 B2.62IntValueStringBuilder70.04 ns1.132 ns1.059 ns2.940.060.010164 B1.00IntValueStringBuilderstackalloc69.39 ns0.459 ns0.430 ns2.910.040.010164 B1.00结论短字符串用StringBuilder有点多此一举了64 B 基本上就是结果字符串的大小测试例子中直接使用内插字符串内存分配最少只有40 B所以一般情况下直接用内插字符串最方便看一下sharplab可以看到在高版本的.Net中内插字符串会转化为DefaultInterpolatedStringHandler这是一个结构体处理器。而在内插字符串中执行ToString()会导致退化成string.Concat()。Unity测试代码usingSystem.Text;usingCysharp.Text;usingNUnit.Framework;usingUnity.PerformanceTesting;publicenumTestState{Idle,Running,Jumping}publicclassIntToStringBenchmark{privatereadonlyTestState_valueTestState.Idle;privatereadonlyint_maxValue100;[Test,Performance]publicvoidIntToString(){Measure.Method((){varval${_value.ToString()}/{_maxValue.ToString()};_val;// 防止编译器优化掉结果}).WarmupCount(10).MeasurementCount(100).GC().Run();}[Test,Performance]publicvoidIntInterpolation(){Measure.Method((){varval${_value}/{_maxValue};_val;}).WarmupCount(10).MeasurementCount(100).GC().Run();}[Test,Performance]publicvoidIntStringBuilder(){Measure.Method((){varstringBuildernewStringBuilder();stringBuilder.Append(_value.ToString());stringBuilder.Append(/);stringBuilder.Append(_maxValue);varvalstringBuilder.ToString();_val;}).WarmupCount(10).MeasurementCount(100).GC().Run();}[Test,Performance]publicvoidIntStringZString(){Measure.Method((){usingvarstringBuilderZString.CreateStringBuilder(true);stringBuilder.Append(_value.ToString());stringBuilder.Append(/);stringBuilder.Append(_maxValue);varvalstringBuilder.ToString();_val;}).WarmupCount(10).MeasurementCount(100).GC().Run();}}测试结果IntInterpolationTime.GC() in UndefinedsMin: 4.00Median: 4.00Max: 11.00Avg: 4.20StdDev: 0.77SampleCount: 110Sum: 462.00Time in MillisecondsMin: 0.02 msMedian: 0.02 msMax: 0.03 msAvg: 0.02 msStdDev: 0.00 msSampleCount: 100Sum: 2.17 msIntStringBuilderTime.GC() in UndefinedsMin: 6.00Median: 6.00Max: 9.00Avg: 6.10StdDev: 0.45SampleCount: 110Sum: 671.00Time in MillisecondsMin: 0.02 msMedian: 0.02 msMax: 0.04 msAvg: 0.02 msStdDev: 0.00 msSampleCount: 100Sum: 2.23 msIntStringZStringTime.GC() in UndefinedsMin: 3.00Median: 3.00Max: 14.00Avg: 3.11StdDev: 1.05SampleCount: 110Sum: 342.00Time in MillisecondsMin: 0.02 msMedian: 0.02 msMax: 0.03 msAvg: 0.02 msStdDev: 0.00 msSampleCount: 100Sum: 1.96 msIntToStringTime.GC() in UndefinedsMin: 4.00Median: 4.00Max: 7.00Avg: 4.05StdDev: 0.31SampleCount: 110Sum: 445.00Time in MillisecondsMin: 0.01 msMedian: 0.02 msMax: 0.03 msAvg: 0.02 msStdDev: 0.00 msSampleCount: 100Sum: 1.80 ms结论内插字符串在内存分配和速度上的表现依然很好。ZString库虽然慢了一丢丢但是内存分配少了很多。