在C#源代码中,最好的字符串分割方法是什么?

41
我很想知道在C#源代码中,将长字符串拆分的最佳实践是什么。这个字符串是:
"string1"+
"string2"+
"string3"

编译期间还是运行时拼接?

10个回答

56

这是在编译时完成的。这与 "string1string2string3" 完全等效。

假设您有:

string x = "string1string2string3"
string y = "string1" + "string2" + "string3"

编译器将执行适当的内部化,使x和y引用相同的对象。
编辑:答案和评论中有很多关于StringBuilder的讨论。许多开发人员似乎认为应该始终使用StringBuilder进行字符串连接。这是一种过度概括——值得理解为什么StringBuilder在某些情况下很好,在其他情况下则不好。

45

如果空格不重要,你可以使用@转义字符在代码中编写多行字符串。 如果您在代码中有一个查询,这非常有用,例如:

string query = @"SELECT whatever
FROM tableName
WHERE column = 1";

这将给你一个带有换行符和制表符的字符串,但对于一个查询来说并不重要。


8

您的示例将在编译时进行连接。所有内联字符串和const字符串变量都会在编译时连接。

需要记住的是,包含任何只读字符串将延迟到运行时进行连接。string.Empty和Environment.NewLine都是只读字符串变量。


4
拼接是在编译时完成的,因此没有运行时开销。

4
以下是如何使用 扩展方法(受 common-tags oneLine 方法启发)的示例...
using System;
using System.Text.RegularExpressions;
using static System.Text.RegularExpressions.RegexOptions;

namespace My.Name.Space
{
    public static class StringHelper
    {
        public static string AsOneLine(this string text, string separator = " ")
        {
            return new Regex(@"(?:\n(?:\s*))+").Replace(text, separator).Trim();
        }
    }
}

...与原样字符串字面值结合使用,用法如下:

var mySingleLineText = @"
    If we wish to count lines of code, we should not regard them
    as 'lines produced' but as 'lines spent'.
".AsOneLine();

请注意,字符串中的空格“内部”保持不变,例如:
// foo      bar hello        world.
var mySingleLineText = @"
    foo      bar
    hello        world.
".AsOneLine();

如果您不想将换行符替换为空格,则将""作为参数传递给扩展方法即可:
// foobar
var mySingleLineText = @"
    foo
    bar
".AsOneLine("");

请注意:由于涉及辅助方法,此字符串连接形式在运行时进行(与使用+运算符在编译时发生的连接形式相反,如接受的答案中所述)。因此,如果性能是一个问题,请选择+。如果您处理的是长语句并且可读性和“易用性”是重点,则上面建议的方法可能值得考虑。

这似乎不允许在字符串内部使用转义引号,例如 "。 - rv.kvetch
嗨,使用文字直接量符号 @ 时,你需要始终使用双引号而不是斜杠("") 来转义引号,例如 @"hello ""{name}"", how are you"; 参见:https://dev59.com/AnRB5IYBdhLWcg3wro2B#556141。 - Felix K.
1
啊,好巧妙的技巧!我改正了,谢谢。 - rv.kvetch

1

这取决于你的需求。一般来说,如果你需要拼接字符串,在运行时获得最佳性能的方法是使用StringBuilder。 如果你在源代码中引用类似 var str = "String1"+"String2" 的内容,它将在编译时转换为字符串 str = "String1String2"。在这种情况下,你就没有任何拼接开销。


你的泛化太过于笼统了 - 如果你可以一次性完成整个连接操作,通常比使用StringBuilder更快(且更易读)。因此,建议使用“x + y + z”而不是new StringBuilder(x).Append(y).Append(z).ToString()。当存在重复连接时,StringBuilder非常有用。 - Jon Skeet
就John的观点再多说一句...循环等情况下,StringBuilder非常有用。对于单个操作集,string.Concat更简单且效果相同。 - Marc Gravell
谢谢Marc - 我的空间用完了 :) 不过我编辑了我的答案,指向了我的StringBuilder文章... - Jon Skeet
“+” 运算符实际上调用了 concat 方法。如果你看一下 StringBuilder 的实现,会发现它更加智能 :) - Tamir

1

如果您要连接许多(超过四个)字符串,那么使用StringBuilder是一个不错的选择。它速度更快。

在上面的示例中,使用String.Concat是在编译时完成的。由于它们是字面字符串,所以编译器对它们进行了优化。

但是,如果您使用变量:

string a = "string1";
string b = "string2";
string c = a + b;

这是在运行时完成的。


“more than 4” 只在循环一组数据时才相关;否则,单个调用 string.Concat(必要时传递数组)是相同的。 - Marc Gravell
你所说的是正确的。 - Sani Huttunen

0

你不能使用 StringBuilder 吗?


1
这样做会使代码更难读,并且性能也会降低。换句话说,这是一件不好的事情。 - Jon Skeet
好的,我认为如果您需要大量字符串拼接,那么建议使用StringBuilder? - Damien
1
如果您在运行时进行大量的字符串拼接,那么是的,建议使用 StringBuilder。但是上面的示例具有静态字符串,因此编译器已将其优化为单个字符串。 - Maxam
即使在运行时进行字符串连接,使用“+”连接两个字符串比使用StringBuilder更快。 - Jon Skeet
我确实说了“很多”=)但你是对的,我应该进一步说明。 - Maxam
如果我们想要保持一个常量字符串(即绑定),StringBuilder 不是一个选项。 - Chesare

0

有很多方法可以实现。 我的最爱是使用 C# 中的字符串方法。 例如:

string s=string.Format("{0} {1} {0}","Hello","By"); 结果为 s="Hello By Hello";


-3

如果你在使用任何数量的字符串,那么StringBuilder会是你最快的选择。

http://dotnetperls.com/Content/StringBuilder-1.aspx

如果你只是处理几个字符串(5个或更少是一个好的规则),使用哪种连接方式速度并不重要。


字符串构建器是更快的运行时解决方案,但给定的表达式最好在编译时评估(我认为这对编译器不应该是一个问题)。 - peterchen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接