[C#] 何时在 .NET Core 中使用 String 与 StringBuilder

27 篇文章 4 订阅
20 篇文章 0 订阅
本文探讨了在.NETCore中使用String和StringBuilder进行字符串操作的最佳实践,包括字符串连接、可重用StringBuilder池、Substring与Append性能对比以及String.Join和StringBuilder.AppendJoin的效率提升。
摘要由CSDN通过智能技术生成

英文原文:https://www.infoworld.com/article/3616600/when-to-use-string-vs-stringbuilder-in-net-core.html

在 .NET Core 中处理字符串时,您会经常使用的两个流行类是 String 和 StringBuilder 类。在使用这两个类构建最小化分配且高性能的应用程序时,您应该了解最佳实践。本文讨论在 C# 中使用字符串时可以遵循的最佳实践。

C# 中使用 String 和 StringBuilder 进行字符串连接

不可变对象是指一旦创建就无法修改的对象。由于字符串是 C# 中的不可变数据类型,因此当组合两个或多个字符串时,会生成一个新字符串。

然而,字符串在 C# 中是不可变类型,而 StringBuilder 是可变项的一个示例。在 C# 中,StringBuilder 是一系列可变的字符,如果需要,可以对其进行扩展以存储更多字符。与字符串不同,修改 StringBuilder 实例不会导致在内存中创建新实例。

当您想要更改字符串时,公共语言运行时会从头开始生成一个新字符串并丢弃旧字符串。因此,如果将一系列字符附加到字符串中,则会在内存中多次重新创建相同的字符串。相比之下,StringBuilder 类为缓冲区空间分配内存,然后将新字符直接写入缓冲区。分配仅发生一次。

考虑以下两种方法:

[Benchmark]
public string StringConcatenationUsingStringBuilder()
{
      StringBuilder stringBuilder = new StringBuilder();
      for (int i = 0; i < NumberOfRuns; i++)
      {
          stringBuilder.AppendLine("Hello World" + i);
      }
      return stringBuilder.ToString();
  }
[Benchmark]
public string StringConcatenationUsingString()
{
    string str = null;
    for (int i = 0; i < NumberOfRuns; i++)
    {
        str += "Hello World" + i;
    }
    return str;
}

图 1 显示了这两种方法的性能基准。
在这里插入图片描述
如图 1 所示,与使用“+”运算符组合两个或多个字符串相比,使用 StringBuilder 连接字符串速度更快,消耗的内存更少,并且在所有代中使用的垃圾回收更少。

请注意,常规字符串连接比使用 StringBuilder 更快,但前提是您一次使用其中几个字符串。如果您使用两个或三个字符串连接,请使用字符串。当您重复修改字符串或将多个字符串连接在一起时,StringBuilder 将提高性能。

简而言之,仅将 StringBuilder 用于大量串联。

在 C# 中使用可重用池减少 StringBuilder 分配

考虑以下两种方法 - 一种方法不使用池创建 StringBuilder 实例,另一种方法使用可重用池创建 StringBuilder 实例。通过使用可重用池,您可以减少分配。当您需要 StringBuilder 实例时,可以从池中获取一个。使用完 StringBuilder 实例后,可以将该实例返回到池中。

[Benchmark]
public void CreateStringBuilderWithoutPool()
{
    for (int i = 0; i < NumberOfRuns; i++)
    {
        var stringBuilder = new StringBuilder();
        stringBuilder.Append("Hello World" + i);
    }
}
[Benchmark]
public void CreateStringBuilderWithPool()
{
    var stringBuilderPool = new
    DefaultObjectPoolProvider().CreateStringBuilderPool();
    for (var i = 0; i < NumberOfRuns; i++)
    {
        var stringBuilder = stringBuilderPool.Get();
        stringBuilder.Append("Hello World" + i);
        stringBuilderPool.Return(stringBuilder);
    }
}

图 2 显示了这两种方法的性能基准。
在这里插入图片描述
正如您在图 2 中看到的,当您使用可重用池时,内存分配会大大减少。

在 C# 中使用 Substring 与 Append 提取字符串

现在让我们比较 String 类的 Substring 方法与 StringBuilder 类的 Append 方法从另一个字符串中提取字符串的性能。

考虑下面的代码片段,它演示了两种方法:一种使用 String 类的 Substring 方法从另一个字符串中提取字符串,另一种使用 StringBuilder 类的 Append 方法执行相同的操作。

[Benchmark]
public string ExtractStringUsingSubstring()
{
    const string str = "This is a sample text";
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < NumberOfRuns; i++)
    {
        stringBuilder.Append(str.Substring(0, 10));
    }
    return stringBuilder.ToString();
}
[Benchmark]
public string ExtractStringUsingAppend()
{
    const string str = "This is a sample text";
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < NumberOfRuns; i++)
    {
        stringBuilder.Append(str, 0, 10);
    }
    return stringBuilder.ToString();
}

图 3 显示了这两种方法的性能基准。
在这里插入图片描述
如图 3 所示,使用 StringBuilder 类的 Append 方法提取字符串比使用 Substring 更快,而且消耗的资源更少。

C# 中使用 String.Join 与 StringBuilder.AppendJoin 连接字符串

当您连接字符串时,请使用 StringBuilder.AppendJoin 代替 String.Join 以减少分配。考虑下面的代码片段,它说明了两种方法 - 一种使用 String.Join 连接字符串,另一种使用 StringBuilder.AppendJoin 执行相同的操作。

[Benchmark]
public string JoinStringsUsingStringJoin()
{
    var stringBuilder = new StringBuilder();
    for (int i = 0; i < NumberOfRuns; i++)
    {
        stringBuilder.Append(string.Join("Hello", ' ', "World"));
    }
    return stringBuilder.ToString();
}
[Benchmark]
public string JoinStringsUsingAppendJoin()
{
    var stringBuilder = new StringBuilder();
    for (int i = 0; i < NumberOfRuns; i++)
    {
        stringBuilder.AppendJoin("Hello", ' ', "World");
    }
    return stringBuilder.ToString();
}

图 4 显示了这两种方法的性能基准。
在这里插入图片描述
当从字符串中提取字符串时,StringBuilder 在连接字符串时比 String 类具有优势。正如您在图 4 中看到的,使用 StringBuilder 类的 AppendJoin 再次比使用 String 类的 Join 更快且资源效率更高。

使用StringBuilder时,还可以设置StringBuilder实例的容量以提高性能。如果您知道要创建的字符串的大小,则可以在创建 StringBuilder 实例时设置初始容量。这可以大大减少内存分配。

最后一点,String.Create 方法是提高 .NET Core 中字符串处理性能的另一种方法。它提供了一种在运行时创建字符串的有效方法。我将在以后的文章中讨论 String.Create。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值