String or StringBuilder return values?

前端 未结 3 2071
死守一世寂寞
死守一世寂寞 2021-02-12 18:44

If I am building a string using a StringBuilder object in a method, would it make sense to:

Return the StringBuilder object, and let the calling code call ToString()?

相关标签:
3条回答
  • 2021-02-12 19:16

    Return the StringBuilder if you're going to further modify the string, otherwise return the string. This is an API question.

    Regarding efficiency. Since this is a vague/general question without any specifics then I think mutable vs. immutable is more important than performance. Mutability is an API issue of letting your API return modifiable objects. String length is irrelevant to this.

    That said. If you look at StringBuilder.ToString with Reflector:

    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;
    }
    

    You can see it may make a copy but if you modify it with the StringBuilder then it will make a copy then (this is what I can tell the point of m_currentThread is because Append checks this and will copy it if it mismatches the current thread).

    I guess the end of this is that if you do not modify the StringBuilder then you do not copy the string and length is irrelevant to efficiency (unless you hit that 2nd if).

    UPDATE

    System.String is a class which means it is a reference type (as opposed to value type) so "string foo;" is essentially a pointer. (When you pass a string into a method it passes the pointer, not a copy.) System.String is mutable inside mscorlib but immutable outside of it which is how StringBuilder can manipulate a string.

    So when ToString() is called it returns its internal string object by reference. At this point you cannot modify it because your code is not in mscorlib. By setting the m_currentThread field to zero then any further operations on the StringBuilder will cause it to copy the string object so it can be modified and not modify the string object it returned in ToString(). Consider this:

    StringBuilder sb = new StringBuilder();
    sb.Append("Hello ");
    
    string foo = sb.ToString();
    
    sb.Append("World");
    
    string bar = sb.ToString();
    

    If StringBuilder did not make a copy then at the end foo would be "Hello World" because the StringBuilder modified it. But since it did make a copy then foo is still just "Hello " and bar is "Hello World".

    Does that clarify the whole return/reference thing?

    0 讨论(0)
  • 2021-02-12 19:16

    I don't think performance should be a factor in this question. Either way someone is going to call sb.ToString() so your going to take the hit someplace.

    The more important question is what is the intention of the method and the purpose. If this method is part of a builder you might return the string builder. Otherwise I would return a string.

    If this is part of a public API I would lean towards returning a string instead of the builder.

    0 讨论(0)
  • 2021-02-12 19:32

    I would say the method should return sb.ToString(). If the logic surrounding the creation of the StringBuilder() object should change in the future it makes sense to me that it be changed in the method not in each scenario which calls the method and then goes on to do something else

    0 讨论(0)
提交回复
热议问题