如果我在方法中使用 StringBuilder 对象构建字符串,那么以下操作是否有意义:

返回StringBuilder对象,并让调用代码调用ToString()?

return sb;

或者通过自己调用 ToString() 返回字符串。

return sb.ToString();

我想如果我们返回小字符串或大字符串,这会有所不同。每种情况下什么是合适的?提前致谢。

编辑:我不打算进一步修改调用代码中的字符串,但 Colin Burnett 说得好。

主要是返回StringBuilder对象和字符串哪个效率更高?是否会返回对字符串的引用或副本?

有帮助吗?

解决方案

如果要进一步修改字符串,则返回 StringBuilder,否则返回字符串。这是一个API问题。

关于效率。由于这是一个模糊/笼统的问题,没有任何具体细节,所以我认为可变与可变。不可变比性能更重要。可变性是让 API 返回可修改对象的 API 问题。字符串长度与此无关。

就是这样说的。如果您使用 Reflector 查看 StringBuilder.ToString:

public override string ToString()
{
    string stringValue = this.m_StringValue;
    if (this.m_currentThread != Thread.InternalGetCurrentThread())
    {
        return string.InternalCopy(stringValue);
    }
    if ((2 * stringValue.Length) < stringValue.ArrayLength)
    {
        return string.InternalCopy(stringValue);
    }
    stringValue.ClearPostNullChar();
    this.m_currentThread = IntPtr.Zero;
    return stringValue;
}

你可以看到它可能会制作一个副本,但如果你用 StringBuilder 修改它,那么它就会制作一个副本(这就是我可以告诉 m_currentThread 的点是因为 Append 会检查它,如果它与当前线程不匹配,则会复制它) 。

我想最终的结果是,如果您不修改 StringBuilder,那么您就不会复制字符串,并且长度与效率无关(除非您遇到第二个 if)。

更新

System.String是一个类,这意味着它是一种参考类型(与值类型相反),因此“字符串foo;”本质上是指针。(当您将字符串传递给方法时,它传递的是指针,而不是副本。)System.String 在 mscorlib 内部是可变的,但在其外部是不可变的,这就是 StringBuilder 操作字符串的方式。

因此,当调用 ToString() 时,它会通过引用返回其内部字符串对象。此时您无法修改它,因为您的代码不在 mscorlib 中。通过将 m_currentThread 字段设置为零,然后对 StringBuilder 的任何进一步操作都将导致它复制字符串对象,以便可以对其进行修改 不修改 ToString() 中返回的字符串对象。考虑一下:

StringBuilder sb = new StringBuilder();
sb.Append("Hello ");

string foo = sb.ToString();

sb.Append("World");

string bar = sb.ToString();

如果 StringBuilder 没有进行复制,那么最后 foo 将是“Hello World”,因为 StringBuilder 修改了它。但既然它确实复制了,那么 foo 仍然只是“Hello”,而 bar 是“Hello World”。

这是否澄清了整个返回/参考的事情?

其他提示

我不认为表现应该成为这个问题的一个因素。无论哪种方式,某人都会调用sb.ToString(),这样你就可以在某个地方接受命中。

更重要的问题是方法的意图和目的是什么。如果此方法是构建器的一部分,则可能返回字符串构建器。否则我会返回一个字符串。

如果这是公共API的一部分,我会倾向于返回字符串而不是构建器。

我想说该方法应该返回sb.ToString()。如果围绕创建StringBuilder()对象的逻辑将来会发生变化,那么对我来说有意义的是,它会在方法中进行更改,而不是在调用方法的每个场景中进行更改,然后继续执行其他操作

StringBuilder 是您方法的实现细节。您应该返回字符串,直到它成为性能问题,此时您应该探索另一种模式(例如 visitor Pattern )可以帮助您引入间接并保护您免受内部实施决策的影响。

字符串始终存储在堆中,因此如果返回类型为字符串,则会返回引用。但是,您不能指望两个相同的字符串具有相同的引用。一般来说,将字符串视为值类型是安全的,即使它实际上是一个引用类型。

我认为这取决于你离开方法后你对字符串做了什么。如果您要继续添加它,那么您可能需要考虑返回一个字符串构建器以提高效率。如果你总是打算在它上面调用.ToString(),那么你应该在方法中进行更好的封装。

我几乎在所有情况下都会返回 string ,特别是如果该方法是公共API的一部分。

如果您的方法只是较大的私有“构建器”的一部分,则会出现例外情况。进程和调用代码将进行进一步的操作。在那种情况下,我可能会考虑返回 StringBuilder

因为你不再修改它了

return sb.ToString();

应该是最有效的

返回sb.ToString()。你的方法应该只关注手头的东西(在这种情况下为我构建一个字符串)并且不会被返回以进一步操纵IMO,你可能会遇到各种各样的问题,而不是处理它。

这取决于您计划对输出进行的操作。我会亲自返回一个字符串。这样,如果您需要在不使用字符串构建器的情况下更改方法,您可以将其作为返回值。

暂时考虑一下,答案更清楚了。询问哪些应该返回的问题确实回答了这个问题。返回对象应该是一个字符串。原因是如果你问这个问题,“当字符串发生时,是否有理由返回StringBuilder对象?”然后答案是否定的。如果有原因,那么返回字符串将是不可能的,因为需要stringbuilder的方法和属性。

如果您需要在字符串中添加更多内容并使用其他与字符串构建器相关的功能,请返回stringbuilder。否则,如果您只是使用字符串本身,则返回字符串。

还有其他更多的技术因素,但这是最关注的问题。

该方法被赋予了一个具体的任务,应该期望它完成它并返回不需要进一步处理的完成结果。只有在真正需要时才返回StringBuilder。在这种情况下,还要在方法名称中添加一些内容,以表明您正在返回特殊内容。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top