This question already has an answer here:
As can be seen here,
String.Join works with raw pointers and uses something called
UnSafeCharBuffer. Why is this? Is a performance optimization?
Is a performance optimization?
In general you should expect that unsafe code is either for low-level unmanaged language interop or for performance optimization. In this case it is the latter.
This then suggests the question:
Why not use the same techniques for StringBuilder?
Different scenarios can be tuned using different optimization techniques; StringBuilders are optimized for their scenarios.
The scenarios are different in several ways.
Join knows ahead of time exactly how many bytes will be returned;
StringBuilder does not.
Join knows that the resulting string will be generated exactly once, but a
StringBuilder has to support the create, append,
ToString, ... workflow efficiently. And so on.