public interface ISimpleStringBuilder
{
ISimpleStringBuilder Append(string value);
ISimpleStringBuilder Clear();
int Lenght { get; }
int Capacity { get; }
}
这是一个非常基本的实现
public class SimpleStringBuilder : ISimpleStringBuilder
{
public const int DefaultCapacity = 32;
private char[] _internalBuffer;
public int Lenght { get; private set; }
public int Capacity { get; private set; }
public SimpleStringBuilder(int capacity)
{
Capacity = capacity;
_internalBuffer = new char[capacity];
Lenght = 0;
}
public SimpleStringBuilder() : this(DefaultCapacity) { }
public ISimpleStringBuilder Append(string value)
{
char[] data = value.ToCharArray();
//check if space is available for additional data
InternalEnsureCapacity(data.Length);
foreach (char t in data)
{
_internalBuffer[Lenght] = t;
Lenght++;
}
return this;
}
public ISimpleStringBuilder Clear()
{
_internalBuffer = new char[Capacity];
Lenght = 0;
return this;
}
public override string ToString()
{
//use only non-null ('\0') characters
var tmp = new char[Lenght];
for (int i = 0; i < Lenght; i++)
{
tmp[i] = _internalBuffer[i];
}
return new string(tmp);
}
private void InternalExpandBuffer()
{
//double capacity by default
Capacity *= 2;
//copy to new array
var tmpBuffer = new char[Capacity];
for (int i = 0; i < _internalBuffer.Length; i++)
{
char c = _internalBuffer[i];
tmpBuffer[i] = c;
}
_internalBuffer = tmpBuffer;
}
private void InternalEnsureCapacity(int additionalLenghtRequired)
{
while (Lenght + additionalLenghtRequired > Capacity)
{
//not enough space in the current buffer
//double capacity
InternalExpandBuffer();
}
}
}
6 回答
如果你想看到一个可能的实现(类似于微软实现到v3.5的那个),你可以在github上看到the source of the Mono one .
在.NET 2.0中,它在内部使用
String
类 .String
仅在System
命名空间之外是不可变的,因此StringBuilder
可以做到这一点 .在.NET 4.0中
String
已更改为使用char[]
.在2.0
StringBuilder
看起来像这样但在4.0中它看起来像这样:
显然它已经从使用
string
变为使用char[]
.编辑:更新了答案,以反映.NET 4中的变化(我刚刚发现) .
接受的答案错过了一英里的标记 . 4.0中
StringBuilder
的重大变化不是从不安全的string
变为char[]
- 事实是StringBuilder
是 now actually a linked-list of StringBuilder instances.这种变化的原因应该是显而易见的:现在永远不需要重新分配缓冲区(这是一项昂贵的操作,因为除了分配更多内存外,还必须将旧缓冲区中的所有内容复制到新缓冲区中) .
这意味着调用
ToString()
现在稍慢,因为需要计算最终字符串,但是现在执行大量的Append()
操作要快得多 . 这适用于StringBuilder
的典型用例:大量调用Append()
,然后调用ToString()
.你可以找到基准here . 结论?新的链表
StringBuilder
使用了更多的内存,但对于典型的用例来说明显更快 .不是 - 它使用内部字符缓冲区 . 只有当缓冲区容量耗尽时,它才会分配新的缓冲区 . 追加操作将简单地添加到此缓冲区,当调用ToString()方法时将创建字符串对象 - 此后,由于每个传统字符串连接操作将创建新字符串,因此它适用于许多字符串连接 . 您还可以指定字符串构建器的初始容量,如果您对它有粗略的了解以避免多次分配 .
Edit :人们指出我的理解是错误的 . Please ignore the answer (我宁愿不删除它 - 它将证明我的无知:-)
我做了一个小样本来演示StringBuilder在.NET 4中是如何工作的 . Contract 是
这是一个非常基本的实现
此代码不是线程安全的,不进行任何输入验证,也不使用System.String的内部(不安全)魔法 . 然而它确实展示了StringBuilder类背后的想法 .
有些单元测试和完整的示例代码可以在github找到 .
如果我在.NET 2中查看.NET Reflector,那么我会发现:
所以它是一个变异的字符串实例......
编辑除了在.NET 4中它是
char[]