문제
테스트 할 테스트 응용 프로그램을 작성하고 StringBuilder 복사 데이터 데이터를 다른 인스턴스로 복사하고 길이가 현재 용량 이상인 경우 ildasm.exe에서 확인하지만 동일하게 보입니다.
StringBuilder를 확인하는 방법은 데이터를 새 인스턴스로 복사하고 지정된 한계로 버퍼를 키우는 방법은 무엇입니까?
해결책
StringBuilder가 어떻게 구현되는지 검사하려면 반사기를 발사하고보십시오. 구현 StringBuilder.Append(string)
다음과 같다
public StringBuilder Append(string value)
{
if (value != null)
{
string stringValue = this.m_StringValue;
IntPtr currentThread = Thread.InternalGetCurrentThread();
if (this.m_currentThread != currentThread)
{
stringValue = string.GetStringForStringBuilder(stringValue, stringValue.Capacity);
}
int length = stringValue.Length;
int requiredLength = length + value.Length;
if (this.NeedsAllocation(stringValue, requiredLength))
{
string newString = this.GetNewString(stringValue, requiredLength);
newString.AppendInPlace(value, length);
this.ReplaceString(currentThread, newString);
}
else
{
stringValue.AppendInPlace(value, length);
this.ReplaceString(currentThread, stringValue);
}
}
return this;
}
섹션을보십시오 NeedsAllocation
, GetNewString
당신이 찾고있는 것을 찾기 위해.
다른 팁
용량은 StringBuilder에 할당 된 인접한 메모리를 나타냅니다. 용량은> = 문자열의 길이 일 수 있습니다. 용량보다 StringBuilder에 더 많은 데이터가 추가되면 StringBuilder는 자동으로 용량을 증가시킵니다. 용량이 초과 되었기 때문에 (연속 메모리가 채워지고 더 이상 버퍼 실이 없음) 더 큰 버퍼 영역이 할당되고 원래 메모리 에서이 새로운 영역으로 데이터가 복사됩니다.
데이터를 새로운 '인스턴스'에 복사하지 않고 새로운 '메모리 위치'에 복사합니다. 인스턴스는 동일하게 유지되지만 새 메모리 위치를 가리 킵니다.
FYI 편집 : 생성 중에 지정되지 않은 경우 StringBuilder의 기본 용량은 16입니다.
StringBuilder의 메모리 위치를보고 싶다면 애플리케이션을 디버그하고 디버그> Windows> 메모리를 사용하여 메모리를 확인할 수 있습니다. STMT가 실행되면 StringBuilder에 저장된 각 바이트의 주소를 실제로 볼 수 있습니다.
프로그램을 프로그래밍 방식으로 가져와야하는 경우 이 링크 도움이 될 수 있습니다.
우리는 StringBuilder가 작동하기 때문에 실제로 테스트하는 것이 아니라 자신의 즐거움을 위해 항상 단위 테스트를 작성할 수 있습니다.
StringBuilder sb = new StringBuilder(10);
Console.WriteLine("Capacity = " + sb.Capacity + " Length = " + sb.Length
+ " MaxCapacity = " + sb.MaxCapacity);
sb.Append("1234567890");
sb.Append("1234567890");
sb.Append("1234567890");
Console.WriteLine("Capacity = " + sb.Capacity + " Length = " + sb.Length
+ " MaxCapacity = " + sb.MaxCapacity);
Assert.AreEqual("123456789012345678901234567890"
, sb.ToString()); // NUnit assert.
당연히 통과하고 다음과 같은 출력이 제공됩니다.
Capacity = 10 Length = 0 MaxCapacity = 2147483647 Capacity = 40 Length = 30 MaxCapacity = 2147483647
StringBuilder가 필요할 때 버퍼를 증가시키는 방식은 StringBuilder의 내부 코드에 의해 처리되는 것입니다. 응용 프로그램의 IL 코드에는 표시되지 않습니다. 컴파일러는 특정 방법으로 StringBuilder가 포함하는 스트링이 얼마나 큰지 알 수 없습니다. 때때로 다를 수 있기 때문입니다.
그러나 StringBuilder 일 때 하다 버퍼를 늘리면 새로운 StringBuilder 인스턴스가 발생하지 않습니다. 그것은 새로운 인스턴스에 맞는 문자열의 내부 표현을 복사 할 수 있습니다 (나는 클래스의 내부 작업이 정확히 어떤 일이 일어나는지 정확히 알지 못합니다).
리플렉터를 사용하여 StringBuilder의 작동 방식을 거의 볼 수 있습니다.
방법을 참조하십시오
StringBuilder Append(string value)
.NET 3.5의 경우 로직은 다음과 같습니다. 버퍼 길이가 새 문자열에 충분하지 않은 경우 최대 (Oldsize * 2, QuestmentSize)와 같은 길이의 새 버퍼를 작성하십시오.
다시 말해, StringBuffer는 버퍼를 두 배로 늘리려고 시도하며 충분하지 않은 경우 버퍼 크기가 새 문자열에 맞게 충분합니다.
오래된 버퍼에 대한 참조가 제거되고 이전 버퍼는 다음 쓰레기 수집으로 재생됩니다.
class Program
{
static void Main()
{
StringBuilder sb = new StringBuilder();
Console.WriteLine(sb.Capacity); //16
for (int i = 0; i < 50; i++)
sb.Append(i + ",");
Console.WriteLine(sb.Capacity); //256
sb = new StringBuilder();
Console.WriteLine(sb.Capacity); //16
}
}