I have not explored it in depth, but I have found that it is a struct
, so it might have a bit performance advantage over StringBuilder
which is a class
.
I wonder why it is marked as obsolete?
string.Create is a better alternative.
@davidfowl
I have a question about string.Create
, for it requires the string length as a parameter, then what if the initialized length (the length of the the initialized part) is less then the string length? if this happened, there would be an uninitialized part left in the string, if we show the string, what would happen?
You'll have null characters left in the string.
@davidfowl
I have tested string with null chars, and find that when I use Console.WriteLine
to show such string, these null chars are just like "blank space" chars and printable chars after null chars can be shown too. Sometimes this is not my expected behavior. I hope the null char could be the terminated flag of a string, no matter what exist after it.
So I propose to add the following properties to the string class:
If we have these properties above, then when we use string.Create
, we could just give a roughly estimated capacity, and don't have to calculate/predict the exact initialized length before actual initialization.
bool string.IsNullTerminated { get; set; }
This conflicts with the idea of strings being considered immutable in .NET, thus I personally am against it.
string.Create
is intended for situations where you know the length of the string in advance, so you can avoid multiple allocations.
InplaceStringBuilder
is a very similar API with roughly the same restrictions. The capacity
parameter of InplaceStringBuilder
's constructor is actually more accurately described as length
. (Source)
If you are in a situation where you cannot calculate the length of the string in advance, then I don't believe there is a BCL solution other than StringBuilder
.
EDIT: If you _absolutely_ want to do this though, you can do the following (but I wouldn't recommend it):
This is dangerous and will inevitably crash any program that does it. Refer to the comments below from .NET team members for more information.
class MutableString
{
public int Length;
public char FirstChar;
public ref char this[int index] => ref Unsafe.Add(ref FirstChar, index);
public ref char GetPinnableReference() => ref FirstChar;
}
// ...
int capacity = 10;
var str = string.Create(capacity, 0, (span, _) =>
{
for (int i = 0; i < 5; i++)
span[i] = "ABCDE"[i];
// You won't see this in the output.
span[7] = '7';
});
Unsafe.As<MutableString>(str).Length = 5;
Console.WriteLine("{0} {1}", str.Length, str);
@DaZombieKiller
Thank you for your example, but I think I can even do it like the following:
C#
public static class StringExtension
{
unsafe public static void SetLength(this string s, int length)
{
fixed (char* p = s)
{
int* n = (int*)(p - 2);
*n = length;
}
}
}
class Program
{
static void Main(string[] args)
{
string s = new string('a', 100);
s.SetLength(10);
Console.WriteLine("{0}:{1}\n", s.Length, s); // the output should be "10:aaaaaaaaaa"
}
}
@ygc369 That is indeed another way to do it, although I find the Unsafe.As
approach to be much more readable (and clearer) than using pointer arithmetic.
Both the suggestions above that are modifying string length are corrupting GC heap. You are likely going to see a crash during next GC. Do not ever do that.
@jkotas That's news to me, I had mainly advised against it due to memory wastage, but if there's potential GC heap corruption then I regret even mentioning it. Could you offer any additional details pertaining to how/why this corrupts the heap for curiosity's sake?
EDIT: Judging by the fact that the crash no longer occurs if Length
is restored before a GC collection, I presume modifying Length
causes the GC to be unaware of the full size of the object, leading to a myriad of problems when moving/freeing the memory.
I presume modifying Length causes the GC to be unaware of the full size of the object, leading to a myriad of problems when moving/freeing the memory.
Yes, that is the problem.
The discussion in https://github.com/HelloKitty/Reinterpret.Net/issues/1 has a lot more details about this.
Most helpful comment
Both the suggestions above that are modifying string length are corrupting GC heap. You are likely going to see a crash during next GC. Do not ever do that.