String 클래스
C#에서 문자열(string)은 큰 따옴표 ("")를 사용하여 표현하고, 단일 문자(char)는 작은따옴표(')를 사용하여 표현한다. 키워드 string은 .NET의 System.String 클래스의 별칭이므로, string 타입 데이터에서 System.String 클래스의 모든 메서드와 속성(Property)를 사용할 수 있다. ex) Substring() 메서드, Length 속성
using System;
namespace CobookApplication
{
class Program
{
static void Main(string[] args)
{
// 문자열(string) 변수
string s1 = "Cheeze";
string s2 = "Ramyun";
// 문자(char) 변수
char c1 = 'A';
char c2 = 'B';
// 문자열 결합
string s3 = s1 + " " + s2;
Console.WriteLine("String: {0}", s3); // Cheeze Ramyun
// System.String 속성, 메서드
string s3substring = s3.Substring(1, 8);
Console.WriteLine("Substring: {0}", s3substring); // Substring: heeze Ra
Console.WriteLine(s3substring.Length) // 13
}
}
}
StringBuilder 클래스
C# 문자열은 Immutable이다. 한번 문자열이 생성되어 메모리에 할당되면 다시 변경하는 것이 불가능하다. 만약 string값을 변경하면 기존의 string이 변경되는 것이 아니라 변경된 값을 가지고 있는 새로운 string을 생성한다. 이렇게 되면 기존 string의 메모리 영역은 참조값이 없어지고 이후 가비지 컬렉터에 의해 시스템에게 반환된다.
string name;
name = "Apple";
name = "Banana";
예를 들어 위와 같이 선언했다면 .NET 시스템은 기존의 string 객체에 값이 변경하는 것이 아니라 새로운 string 객체를 생성하여 "Banana"라는 데이터로 초기화한 후 이를 변수명 name에 할당한다. 변수 name은 내부적으로는 전혀 다른 메모리를 갖는 객체가 된다.
.NET의 문자열 작업은 고도로 최적화되어 있기 때문에 대부분의 경우 성능에 큰 영향을 주지 않지만, String 클래스는 Immutable이기 때문에, 타이트 루프에서 문자열 변경 작업이 빈번할 경우 추가적인 메모리 오버헤드와 가비지 컬렉팅으로 인한 성능 저하가 발생할 가능성이 있다. 이를 보완하기 위해서 마이크로소프트에서는 오버헤드 없이 스트링 객체를 조작하기 위한 또 하나의 클래스 StringBuilder를 제공한다.
StringBuilder는 Mutable 타입으로 문자열 갱신이 많은 곳에서 자주 사용되는데 이는 이 클래스가 별도의 메모리를 생성, 소멸하지 않고 일정한 버퍼를 갖고 문자열 갱신을 효율적으로 처리하기 때문이다. 특히 루프 안에서 계속 문자열을 추가 변경하는 코드에서는 string 대신 StringBuilder를 사용해야 한다.
System.Text.StringBuilder sb = new System.Text.StringBuilder("Apple");
sb.Clear();
sb.Append("Banana");
System.Console.WriteLine(sb.ToString()); // Banana
System.Console.WriteLine(sb[0]); // B
using System;
using System.Text;
namespace CobookApplication
{
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
sb.Append("Name");
for (int i = 1; i <= 5; i++)
{
sb.Append(i.ToString());
sb.Append(", ");
}
string s = sb.ToString();
Console.WriteLine(s); // Name1, Name2, Name3, Name4, Name5
}
}
}
String vs StringBuilder
그럼 StringBuilder가 String보다 좋은가? 무조건 그런 것은 아니다.
일반적으로 StringBuilder가 String보다 더 나은 성능을 제공하지만 문자열을 조작할 때마다 String을 StringBuilder로 대체하는 것은 좋지 않다.
성능(Performance)는 문자열의 크기, 새 문자열에 할당할 메모리의 양, 코드가 실행되는 시스템 그리고 작업 유형에 의존하여 달라지기 때문에 StringBuilder가 보다 나은 성능 개선을 제공하는지 안 하는지 테스트를 해보는 것이 좋다.
+
string.Concat() 메서드는 4개의 문자열을 인수로 가질수 있고, 미리 만들어진 인수 4개 까지는 비관리 코드를 사용하여 빠르게 처리할 수 있도록 구현되어 있다. 따라서 문자열 4개까지(그보다 조금 많아도 괜찮다.)는 그냥 + 연산자 혹은 string.Concat() 메서드를 사용하면 된다. 단, 이것은 + 연산자의 경우로 += 연산자를 사용하는 경우에는 그런 도움을 받을 수 없다.
+
string.Format()을 사용한 문자열 포메팅은 가장 비효율적인 방법이다. 굳이 사용한다면 미리 ToString()을 해서 박싱이 발생하지 않도록 하자.
String을 사용하면 좋은 경우
- 문자열의 변경 횟수가 적은 경우, 성능 향상이 미미하다.
- 문자열 리터럴을 사용하여 고정된 수의 연결 작업을 수행하는 경우
- String 클래스의 메서드를 사용해야 하는 경우. (예를 들어, StringBuilder 클래스에는 없고 String 클래스에만 있는 IndexOf나 StrartsWith와 같은 메서드를 사용해야 하면 StringBuilder를 String으로 변환(Convert) 해야 하는데, 이렇게 되면 StringBuilder로부터 얻는 성능상 이점에 부정적 영향을 준다.)
StringBuilder를 사용하면 좋은 경우
- 문자열의 변경 횟수가 많은 경우 (예를 들어, 많은 수의 루프를 사용하는 경우)
- 문자열의 변경 횟수를 알 수 없는 경우 (예를 들어, 예측할 수 없는 사용자 입력의 수를 연결해야 하는 경우)
출처
https://learn.microsoft.com/en-us/dotnet/api/system.text.stringbuilder?view=net-7.0
https://kukuta.tistory.com/413
https://overworks.github.io/unity/2018/08/30/finding-best-string-concatenation.html
'C#' 카테고리의 다른 글
[C#] 상수 const & readonly (0) | 2023.03.30 |
---|---|
[C#] 네이밍 룰 (0) | 2023.03.28 |
[C#] 지역 변수, 전역 변수 (1) | 2023.03.28 |
[C#] 2. C# 참조 타입과 값 타입, 박싱과 언박싱 (0) | 2022.11.18 |
[C#] 1. C# 기초 (0) | 2022.11.17 |