字符串拼接问题的最佳解决方案
ZString:零分配的.NET Core和Unity字符串构建器
ZString
项目地址:https://gitcode.com/gh_mirrors/zs/ZString/?utm_source=artical_gitcode&index=top&type=card&webUrl&isLogin=1
此图表比较了以下代码:
- “x:” + x + " y:" + y + " z:" + z
- ZString.Concat(“x:”, x, " y:“, y, " z:”, z)
- string.Format(“x:{0} y:{1} z:{2}”, x, y, z)
- ZString.Format(“x:{0} y:{1} z:{2}”, x, y, z)
- new StringBuilder(), Append(), .ToString()
- ZString.CreateStringBuilder(), Append(), .ToString()
C#编译器会将"x:" + x + " y:" + y + " z:" + z转化为String.Concat(new[]{ “x:”, x.ToString(), " y:“, y.ToString(), " z:”, z.ToString() }),其中每个.ToString和参数数组都会产生分配。而string.Format调用String.Format(string, object, object, object)导致每个参数都要经历int到object的装箱。
所有ZString方法仅分配最终字符串。此外,ZString允许访问内部缓冲区,当输出目标具有无字符串API(如Unity TextMeshPro的SetCharArray)时,可以实现完全零分配。
Unity使用:
下载ZString.Unity.x.x.x.unitypackage,直接导入Unity
全部导入后也许你的项目中之前就存在这个文件
System.Runtime.CompilerServices.Unsafe
那么重复导入后会报错
一般来说删掉新导入的文件就行,跟之前的公用
ZString 使用了一些底层优化技术,比如Span 和内存池,这些都需要用到 System.Runtime.CompilerServices.Unsafe 来绕过一些 .NET 的安全限制以获得更高性能(比如直接操作内存)。很多 SDK(比如 AppsFlyer、Firebase、Addressables 等)都会附带它。
常用方式
using Cysharp.Text;
using UnityEngine;public class ZStringTest : MonoBehaviour
{void Start(){///--------------------Format----------------------// 基本使用string name = "Player";int score = 100;int x = 1;int y = 2;int z = 3;// 普通字符串拼接(GC 会产生垃圾)string s1 = "Name: " + name + ", Score: " + score;//也会有装箱操作string s = $"Name: {name}, Score: {score}";// ZString 拼接(无 GC)string s2 = ZString.Format("Name: {0}, Score: {1}", name, score);//输出:1,2,3Debug.Log(ZString.Join(',', x, y, z));//输出:123Debug.Log(ZString.Concat(x, y, z));//输出:Name: Player, Score: 100Debug.Log(s2);///--------------------StringBuilder-----------------using (var sb = ZString.CreateStringBuilder()){sb.Append("This is ");sb.Append(2025);sb.Append(" test.");string result = sb.ToString(); // 一次性生成//输出:This is 2025 test.Debug.Log(result);} // 自动释放内存池///--------------------TextMeshPro-----------------// 在Unity中,直接写入TextMeshPro,避免完全分配字符串tmp.SetTextFormat("Position: {0}, {1}, {2}", x, y, z);// 准备格式,返回值应存储在字段(如RegexOptions.Compile)var prepared = ZString.PrepareUtf16<int, int>("x:{0}, y:{1:000}");_ = prepared.Format(10, 20);// C# 8.0,使用声明// 创建Utf8 StringBuilder,直接构建Utf8以避免编码using var sb2 = ZString.CreateUtf8StringBuilder();sb2.AppendFormat("foo:{0} bar:{1}", x, y);// 直接写入流或dest来避免分配await sb2.WriteToAsync(stream);sb2.CopyTo(bufferWritter);sb2.TryCopyTo(dest, out var written);}
}