C# 문자열 보간과 FormattableString
기본 문자열 보간
섹션 제목: “기본 문자열 보간”string name = "Alice";int age = 30;string msg = $"이름: {name}, 나이: {age}";// → "이름: Alice, 나이: 30"중괄호 안에 임의의 C# 표현식을 사용할 수 있습니다.
double price = 9.9;string s = $"가격: {price:C2}"; // 통화 형식: ₩9.90string t = $"날짜: {DateTime.Now:yyyy-MM-dd}";string u = $"결과: {(price > 5 ? "비쌈" : "저렴")}";FormattableString
섹션 제목: “FormattableString”$"" 리터럴을 FormattableString으로 받으면 형식 문자열과 인자를 분리해 처리할 수 있습니다.
FormattableString fs = $"Hello, {name}! Age: {age}";
Console.WriteLine(fs.Format); // "Hello, {0}! Age: {1}"Console.WriteLine(fs.ArgumentCount); // 2Console.WriteLine(fs.GetArgument(0)); // "Alice"Console.WriteLine(fs.ToString()); // "Hello, Alice! Age: 30"
// 로케일 지정 출력string invariant = fs.ToString(System.Globalization.CultureInfo.InvariantCulture);SQL 인젝션 방지 패턴
섹션 제목: “SQL 인젝션 방지 패턴”// 위험: 직접 문자열 연결 → SQL 인젝션string sql = $"SELECT * FROM users WHERE name = '{userInput}'";
// 안전: FormattableString으로 파라미터화FormattableString query = $"SELECT * FROM users WHERE name = {userInput}";DbCommand cmd = CreateSafeCommand(query);
static DbCommand CreateSafeCommand(FormattableString fs) { var cmd = connection.CreateCommand(); cmd.CommandText = Regex.Replace(fs.Format, @"\{(\d+)\}", "@p$1"); for (int i = 0; i < fs.ArgumentCount; i++) cmd.Parameters.AddWithValue($"@p{i}", fs.GetArgument(i)); return cmd;}.NET 6+ InterpolatedStringHandler
섹션 제목: “.NET 6+ InterpolatedStringHandler”.NET 6부터 컴파일러가 보간 문자열을 InterpolatedStringHandler로 변환해 불필요한 중간 문자열 생성을 방지합니다.
// .NET 6+: 조건이 false면 보간 표현식 자체를 평가하지 않음logger.LogDebug($"계산 결과: {ExpensiveComputation()}");// Debug 레벨이 비활성화되어 있으면 ExpensiveComputation() 호출 안 됨커스텀 핸들러 구현:
[InterpolatedStringHandler]public ref struct LogHandler { private StringBuilder _sb; private readonly bool _enabled;
public LogHandler(int literalLength, int formattedCount, bool enabled, out bool shouldAppend) { _enabled = enabled; shouldAppend = enabled; _sb = enabled ? new StringBuilder(literalLength) : default!; }
public void AppendLiteral(string s) { if (_enabled) _sb.Append(s); } public void AppendFormatted<T>(T value) { if (_enabled) _sb.Append(value); } public override string ToString() => _sb?.ToString() ?? "";}다중 줄 보간 (C# 11)
섹션 제목: “다중 줄 보간 (C# 11)”// C# 11 raw string literal + 보간var json = $""" {{ "name": "{name}", "age": {age} }} """;""" 안에서는 {{, }}이 필요 없고 {, }은 그대로 사용됩니다.
성능 비교
섹션 제목: “성능 비교”| 방식 | 특징 |
|---|---|
string.Format | 전통적, 박싱 발생 |
$"" (문자열 보간) | 컴파일러가 string.Format으로 변환 |
StringBuilder | 대량 연결에 유리 |
InterpolatedStringHandler | .NET 6+, 조건부 평가 생략 가능 |
string.Create | 할당 최소화, 저수준 제어 |
$""보간은 가독성이 좋고 컴파일 타임에 검증됨FormattableString으로 받으면 형식 문자열과 인자를 분리 처리 가능 → SQL/쿼리 파라미터화에 유용- .NET 6+
InterpolatedStringHandler로 로깅 등에서 불필요한 문자열 생성 방지 - C# 11 raw string literal과 결합하면 JSON/XML 템플릿 작성이 편리