前言

在C#编程中字符串拼接是一种常见且基础的操作,广泛应用于各种场景,如动态生成SQL查询、构建日志信息、格式化用户显示内容等。然而,不同的字符串拼接方式在性能和内存使用上可能存在显著差异。今天咱们一起来看看在C#中字符串拼接的常见6种方式及其使用BenchmarkDotNet进行性能分析对比。

BenchmarkDotNet

BenchmarkDotNet是一个基于.NET开源、功能全面、易于使用的性能基准测试框架,它为.NET开发者提供了强大的性能评估和优化能力。通过自动化测试、多平台支持、高级统计分析和自定义配置等特性,BenchmarkDotNet帮助开发者更好地理解和优化软件系统的性能表现。

拼接基础数据

private const int IterationCount = 1000;
private const string StringPart1 = "追逐时光者";
private const string StringPart2 = "DotNetGuide";
private const string StringPart3 = "DotNetGuide技术社区";
private readonly string[] _stringPartsArray = { "追逐时光者", "DotNetGuide", "DotNetGuide技术社区" };

+操作符

        /// <summary>
        /// 使用 + 操作符拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string PlusOperator()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += StringPart1 + " " + StringPart2 + " " + StringPart3;
            }
            return result;
        }

$内插字符串

        /// <summary>
        /// 使用 $ 内插字符串拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string InterpolatedString()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += $"{StringPart1} {StringPart2} {StringPart3}";
            }
            return result;
        }

String.Format

        /// <summary>
        /// 使用string.Format()拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string StringFormat()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += string.Format("{0} {1} {2}", StringPart1, StringPart2, StringPart3);
            }
            return result;
        }

String.Concat

        /// <summary>
        /// 使用string.Concat()拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string StringConcat()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += string.Concat(StringPart1, " ", StringPart2, " ", StringPart3);
            }
            return result;
        }

String.Join

        /// <summary>
        /// 使用string.Join()拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string StringJoin()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += string.Join(" ", _stringPartsArray);
            }
            return result;
        }

StringBuilder

        /// <summary>
        /// 使用StringBuilder拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string StringBuilder()
        {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < IterationCount; i++)
            {
                stringBuilder.Append(StringPart1);
                stringBuilder.Append(" ");
                stringBuilder.Append(StringPart2);
                stringBuilder.Append(" ");
                stringBuilder.Append(StringPart3);
            }
            return stringBuilder.ToString();
        }

性能基准对比测试完整代码

    [MemoryDiagnoser]//记录内存分配情况
    public class StringConcatenationBenchmark
    {
        private const int IterationCount = 1000;
        private const string StringPart1 = "追逐时光者";
        private const string StringPart2 = "DotNetGuide";
        private const string StringPart3 = "DotNetGuide技术社区";
        private readonly string[] _stringPartsArray = { "追逐时光者", "DotNetGuide", "DotNetGuide技术社区" };

        /// <summary>
        /// 使用 + 操作符拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string PlusOperator()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += StringPart1 + " " + StringPart2 + " " + StringPart3;
            }
            return result;
        }

        /// <summary>
        /// 使用 $ 内插字符串拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string InterpolatedString()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += $"{StringPart1} {StringPart2} {StringPart3}";
            }
            return result;
        }

        /// <summary>
        /// 使用string.Format()拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string StringFormat()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += string.Format("{0} {1} {2}", StringPart1, StringPart2, StringPart3);
            }
            return result;
        }

        /// <summary>
        /// 使用string.Concat()拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string StringConcat()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += string.Concat(StringPart1, " ", StringPart2, " ", StringPart3);
            }
            return result;
        }

        /// <summary>
        /// 使用string.Join()拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string StringJoin()
        {
            string result = string.Empty;
            for (int i = 0; i < IterationCount; i++)
            {
                result += string.Join(" ", _stringPartsArray);
            }
            return result;
        }

        /// <summary>
        /// 使用StringBuilder拼接字符串
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public string StringBuilder()
        {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < IterationCount; i++)
            {
                stringBuilder.Append(StringPart1);
                stringBuilder.Append(" ");
                stringBuilder.Append(StringPart2);
                stringBuilder.Append(" ");
                stringBuilder.Append(StringPart3);
            }
            return stringBuilder.ToString();
        }
    }

性能基准对比测试分析报告

Method Mean Error StdDev Gen0 Gen1 Allocated
PlusOperator 2,066.28 us 35.761 us 63.566 us 5238.2813 789.0625 32283.12 KB
InterpolatedString 1,984.56 us 29.949 us 28.014 us 5238.2813 789.0625 32283.12 KB
StringFormat 2,112.02 us 25.020 us 23.404 us 5257.8125 777.3438 32369.06 KB
StringConcat 2,027.09 us 28.300 us 26.472 us 5257.8125 777.3438 32369.06 KB
StringJoin 2,017.36 us 27.111 us 22.639 us 5257.8125 777.3438 32369.06 KB
StringBuilder 13.63 us 0.065 us 0.058 us 23.2544 4.6387 143.96 KB

说明:

  • Mean: 所有测量值的算术平均值。
  • Error: 99.9% 置信区间的一半。
  • StdDev: 所有测量值的标准差。
  • Gen0: 第 0 代 GC 每 1000 次操作收集一次。
  • Gen1: 第 1 代 GC 每 1000 次操作收集一次。
  • Gen2: 第 2 代 GC 每 1000 次操作收集一次。
  • Allocated: 每次操作分配的内存(仅托管内存,包含所有内容,1KB = 1024B)。
  • 1 ms: 1 毫秒(0.001 秒)。

性能基准对比测试结论

从上面的性能基准对比测试分析报告来看StringBuilder是性能最好的字符串拼接方式,特别是在需要频繁进行拼接的场景中。其他方式(如+操作符$内插字符串String.FormatString.ConcatString.Join)在性能上相对较差,因为它们会导致多次内存分配和复制。

因此我们在选择字符串拼接方式时,应该根据具体场景和需求进行选择。如果性能是关键因素,并且需要频繁进行拼接,则应使用StringBuilder。如果代码简洁性和易读性更重要,并且拼接次数较少,则可以考虑使用其他方式。

C#字符串拼接的几种方式及其性能分析对比的更多相关文章

  1. JS几种变量交换方式以及性能分析对比

    前言 "两个变量之间的值得交换",这是一个经典的话题,现在也有了很多的成熟解决方案,本文主要是列举几种常用的方案,进行大量计算并分析对比. 起由 最近做某个项目时,其中有一个需求是 ...

  2. JS几种数组遍历方式以及性能分析对比

    前言 这一篇与上一篇 JS几种变量交换方式以及性能分析对比 属于同一个系列,本文继续分析JS中几种常用的数组遍历方式以及各自的性能对比 起由 在上一次分析了JS几种常用变量交换方式以及各自性能后,觉得 ...

  3. Python中字符串拼接的三种方式

    在Python中,我们经常会遇到字符串的拼接问题,在这里我总结了三种字符串的拼接方式:     1.使用加号(+)号进行拼接 加号(+)号拼接是我第一次学习Python常用的方法,我们只需要把我们要加 ...

  4. Python字符串拼接的五种方式

    第一种 通过加号(+)的形式 print('第一种方式通过加号形式连接 :' + 'love'+'Python' + '\n') 第二种 通过逗号(,)的形式 print('第二种方式通过逗号形式连接 ...

  5. java字符串拼接的几种方式

    1. plus方式 当左右两个量其中有一个为String类型时,用plus方式可将两个量转成字符串并拼接. String a="";int b=0xb;String c=a+b;2 ...

  6. C#字符串拼接的三种方式

    static void Main(string[] args) { string name = "asher"; //方法1 string str1 = "hello & ...

  7. [Golang]字符串拼接方式的性能分析

    本文100%由本人(Haoxiang Ma)原创,如需转载请注明出处. 本文写于2019/02/16,基于Go 1.11.至于其他版本的Go SDK,如有出入请自行查阅其他资料. Overview 写 ...

  8. C 语言字符串连接的 3种方式

    C 语言字符串连接的 3种方式 #include<stdio.h> #include<stdlib.h> #include<string.h> char *join ...

  9. Js 字符串拼接的两种方法

    字符串拼接的两种方法 用数组的方法的好处是:避免变量重新定义.赋值 <!DOCTYPE html> <html lang="en"> <head> ...

  10. C++读取字符串数据的两种方式

    C++读取字符串数据的两种方式 对于同样的样例输入: ladder came tape soon leader acme RIDE lone Dreis peat ScAlE orb eye Ride ...

随机推荐

  1. excel江湖异闻录--自序

    本书原名<excel从高手到小白>,取这个名字是因为,当我只会几个有关excel的快捷键和简单函数时我放眼我所在的"井口",当真有种天下谁与争锋的感觉,的确就我周围的伙 ...

  2. uprobe的使用浅析

    uprobe是linux内核提供的一种trace用户态函数的机制 可以在不对二进制重新编译的情况下进行trace特定函数 本文描述了uprobe的基本使用方法 使用方法 官方的指引是这样的, 详细的可 ...

  3. 二、java之面向对象

    面向对象 面向对象编程(Object-Oriented Programming,OOP) 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据 三大特性: ◆封装 ◆◆封装的概念 程序 ...

  4. tmux从入门到装x

    原文: https://blog.csdn.net/CSSDCC/article/details/121231906 安装方法: # Ubuntu 或 Debian $ sudo apt-get in ...

  5. 什么是前后端分离应用(Full-stack Separation),想当然就会理解错

    前后端分离应用指的是将应用的前端部分(用户界面与交互逻辑)和后端部分(业务逻辑.数据处理.服务器响应)拆分成独立的模块,各自通过 API 进行通信.这种架构设计的目的是提高开发效率.增强可扩展性和灵活 ...

  6. Sql高级

    sql高级 1. 索引与视图 常见的数据结构 栈:先进后出 队列:先进先出 数组:查询快,根据下标查询 链表:分为双链表与单链表.单链表指向下一个数据的存储位置:双链表指向前一个与下一个数据的存储位置 ...

  7. DHorse v1.6.0 发布,基于 k8s 的发布平台

    版本说明 新增特性 支持Codeup(阿里云云效)代码仓库: 支持环境的自动部署: 优化特性 管理员角色部署环境部需要审批: 优化页面展示: 升级指南 升级指南 DHorse介绍 DHorse是一个轻 ...

  8. .NET + 微信小程序开源多功能电商系统

    前言 推荐一款基于微信小程序.LayUI 和 .NET 平台的多功能电商系统,支持二次开发和扩展,帮助大家轻松快速搭建一个功能全面且易于管理的在线商城. 项目介绍 该项目不仅包含了微信小程序前端,还配 ...

  9. OAS常见错误

    body { font-family: Arial, sans-serif; line-height: 1.6; margin: 20px } h1, h2 { color: rgba(51, 51, ...

  10. 12万字的java面试题及答案整理(2024新版)

    前言 本来想着给自己放松一下,刷刷博客,慕然回首,final有哪些用法?static都有哪些用法?java的精度算法?java运算逻辑?异常处理?似乎有点模糊了,那就大概看一下Java基础面试题吧.好记 ...