본문 바로가기
프로그래밍/Effective C#

Effective C# Item 4 : string.Format()을 보간 문자열로 대체하라

by bantomak 2023. 10. 23.

string.Format()을 보간 문자열로 대체하라

컴퓨터 프로그램을 최초로 작성하기 시작한 시절부터 개발자들은 컴퓨터에 저장된 정보를 사람이 읽을 수 있는 형태로 변경하는 코드를 꾸준히 개발해 왔다. C#에도 C에서 널리 사용되던 API를 그대로 수용하여 동일한 방법으로 문자열을 만들 수 있었다. 이제는 이러한 방법에서 벗어나 C# 6.0에 새롭게 도입된 문자열 보간 기능을 사용해 보자.

 

고전적인 문자열 포매팅 방식 대비 보간 문자열의 장점

  • 코드 가독성이 대폭 향상되었다.
  • 컴파일러 입장에서는 정적 타입 검사를 수행할 수 있기 때문에 실수를 미연에 방지할 수 있다.
  • 기존 방식에 비해 문자열을 생성하기 위한 표현식이 더 풍부해졌다.

 

기존에 널리 사용되던 string.Format() 또한 문자열 변환 과정을 잘 수행하지만, 생성된 문자열을 직접 출력해 보고 올바른 형태인지를 눈으로 직접 확인하기 전까지는 코드를 제대로 작성했는지 쉽게 짐작하기 어려웠다. 그 이유는 이 메서드가 포맷 문자열과 인자 리스트를 분리하여 전달하는 구조이기 때문이다. 또한 이 메서드는 포맷 문자열에 나타낸 인자의 개수와 실제로 전달되는 인자의 개수가 정확하게 일치하는지를 확인하지 않는다. 자칫 실수하여 필요한 인자를 누락하면 런타임에 예외가 발생한다.

 

게다가 string.Format()의 예에서와 같이 포멧 문자열과 출력할 내용을 담고 있는 배열을 나누어 전달하면 인자의 순서가 올바른지 확인하기도 어렵다. 결국 정확히 문자열이 생성되는지를 확인하기 위해서는 항상 코드를 실행해 보고 그 내용을 직접 확인해야만 한다.

 

보간 문자열을 사용하려면 문자열 앞에 '$'를 붙이면 된다. 문자열로 변경할 표현식은 { } (중괄호) 내에 둔다. 이를 대체 문자열이라 하는데 이런 형식을 띠는 덕분에 코드의 가독성이 상당히 좋다. 어느 부분이 어떻게 대체될지 바로 알 수 있기 때문에 결과를 예측하기도 쉽다. 문자열로 변경할 변수들을 다른 배열로 나누어 전달하는 방식도 아니기 때문에 인자의 개수를 틀리게 전달할 가능성이 없으며 출력할 위치를 잘못 지정할 가능성도 없다.

 

약간의 문법 설탕(Syntax Sugar)으로 아주 괜찮은 기능을 구현했다고 생각한다. 실제 코드를 작성할 때 이 기능을 어떻게 활용할 수 있을지 몇 가지 예를 살펴보면 장점이 더 확연하게 드러날 것 같다.

 

문자열 보간 기능에 대해서 세부적인 예를 살펴보기에 앞서 대체 문자열에서 사용하는 표현식의 제약 사항부터 살펴보자. 사실 대체 문자열에서 사용하는 코드를 '표현식(Expression)'이라고 하는 것은 상당히 조심스러운데, 이는 if/else나 while과 같이 제어 흐름을 변경하는 코드는 쓸 수 없기 때문이다. 만일 이러한 제어 프름이 필요하다면 다른 메서드를 정의하여 관련 기능을 구현하고, 대체 문자열에서 그 메서드를 호출하는 방법을 취해야 한다.

 

Console.WriteLine($"The value of pi is {Math.PI}");

 

사용자가 문자열 보간 기능을 사용하더라도 실제 C# 컴파일러는 param을 이용하여 object배열을 전달하는 기존 포매팅 함수를 호출하도록 코드를 생성한다. Math.PI는 double이므로 값 타입이다. 따라서 이를 object 타입으로 변경하려면 박싱을 수행해야 한다. 이런 이유로 이 값은 코드를 너무 자주 사용하거나 루프 내에서 사용하게 되면 성능에 좋지 않은 영향을 미칠 수 있다. (아이템 9: 박싱과 언박싱을 최소화하라 참조) 따라서 다음과 같이 전달할 인자를 사전에 문자열로 변경하면 값 타입이 박싱 되는 것을 피할 수 있다.

 

Console.WriteLine($"The value of pi is {Math.PI.ToString()}");

기본으로 제공되는 ToString() 메서드가 반환하는 문자열이 썩 유용하지 않은 경우가 있다. 이 경우 문자열을 어떻게 포매팅할 것인지를 표현하기 위해서 추가적으로 인자를 전달할 수 있다.

 

Console.WriteLine($"The value of pi is {Math.PI.ToString("F2")}");

 

만약 더 정밀하게 문자열을 포매팅하려면 포맷 문자열을 추가하거나 반환된 문자열을 다시 한번 변경할 수도 있다. 먼저 내장된 표준 포맷 문자열을 사용하는 방법부터 살펴보자. { } 사이에 ':' 포맷 문자열을 추가하면 된다.

 

Console.WriteLine($"The value of pi is {Math.PI:F2}");

 

C#에 이미 익숙한 개발자라면 ':' 기호가 조건 표현식을 나타내는 용도로도 사용되는 것을 알 것이다. 이런 이유로 조건 표현식을 문자열 보간 기능과 같이 사용하게 되면 약간의 충돌이 발생한다. C#은 ':' 포맷 문자열의 시작을 나타내는 것으로 판단하기 때문이다. 따라서 다음과 같이 코드를 작성하면 컴파일 오류가 발생한다.

 

Console.WriteLine($"The value of pi is {round ? Math.PI.ToString() : Math.PI.ToString("F2")}");

 

앞의 코드를 컴파일되도록 변경하려면 컴파일러에게 ':' 포맷 문자열이 아니라 조건 표현식의 일부임을 알려줘야 하는데 다음과 같이 간단히 괄호를 사용하면 된다.

 

Console.WriteLine($"The value of pi is {(round ? Math.PI.ToString() : Math.PI.ToString("F2"))}");

 

문자열 보간 기능을 이용하여 문자열을 포매팅하면 매우 강력한 힘을 발휘한다. 문자열 보간 기능에서 { } 내의 표현식은 앞서 살펴본 것과 같이 그 자체만을 도 이미 유효한 C# 표현식이다. 이런 측면에서 보면 앞서 살펴본 예들은 너무 기초적이다. 다음 코드를 살펴보자. 값이 누락된 경우 명쾌하게 처리하기 위해서 null 조건 연산자(null conditional operator)와 null 병합 연산자(null propagation operator)를 함께 사용했다.

 

Console.WriteLine($"The customer's name is {c?.Name ?? "Name is missing"}");

 

보간 문자열의 표현식을 중첩해서도 사용할 수 있다. { } 문자 사이의 모든 구문은 C# 코드의 일부인 동시에 표현식으로 간주된다({ } 내에서 ':'을 사용하는 경우가 유일한 예외에 해당한다).

 

LINQ 쿼리 구문과 문자열 보간 기능을 함께 사용하기도 한다. 다음 코드는 보간 문자열을 이용하여 출력 서식을 지정한 예다.

 

var output = $@"The First five item are: {src.Take(5).Select(n => $@"Item: {n.ToString()}").Aggregate((c, a) => $@{c}{Environment.NewLine}{a})}";

 

실제로 프로그램을 작성할 때 이처럼 복잡한 코드를 작성하는 경우는 거의 없을 것이다. 앞의 예는 보간 문자열이 C#과 열 마나 잘 결합되는지를 보여주기 위한 용도에 지나지 않는다. 문자열 보간 기능은 ASP.NET MVC의 Razor View 엔진에도 통합됐다. 이를 이용하면 웹 응용 프로그램 내에서 HTML 결과물을 훨씬 쉽게 생성할 수 있다. 템플릿을 이용하여 생성한 기본 MVC 응용프로그램에서도 문자열 보간 기능의 예를 찾아볼 수 있다. 다음 코드는 현재 로그인한 사용자에 대한 정보를 표시하는 코드다.

 

<a asp-controller="Manager" asp-action="Index" title="Manager">Hello@User.GetUserName()!</a>

 

즉, 웹 응용프로그램에서 HTML 페이지를 생성할 때에도 문자열 보간 기능을 사용할 수 있으며 이를 이용하면 원하는 출력 결과를 더 간결하게 표현할 수 있다.

 

이 예는 문자열 보간 기능의 강력함을 드러내는 데 부족함이 없어 보인다. 그리고 전통적 방식의 문자열 포매팅 기능보다 문자열 보간 기능이 훨씬 편리하다는 것을 잘 보여준다. 어떤 경우라도 문자열 보간 기능의 결과가 문자열이라는 사실을 잊어서는 안 된다. 모든 값이 대체되고 나면 단일의 문자열만이 남을 뿐이다. 이런 사실은 SQL 쿼리문을 생성하는 경우에 간혹 혼동을 일으키기도 한다. 문자열 보간 기능은 매개변수화된 SQL 쿼리를 생성하지 않으며 단일의 문자열을 만들 뿐이다. 이 때문에 SQL 명령을 만들 때 문자열 보간 기능을 사용하는 것은 그리 추천할 만한 방식이 아니다. 나중에 객체나 데이터로 재해석이 필요한 문자열을 생성해야 하는 경우라면 문자열 보간 기능을 사용할 때 각별히 주의해야 한다.

 

함께 읽으면 좋은 글

 

C# 숫자 서식 지정자(Number Format Specifier)

표준 출력 형식의 문법 {n,w:tp} 예시 : {0,10:N2} 키워드 명칭 n 인자 Argument w 출력 범위 Width t 데이타 타입 Data Type p 정확도 Precision decimal val = 1234.5678M; string s = string.Format("{0,10:N2}", val); // 출력: " 1,234.

jettstream.tistory.com

 

출처

 

이펙티브 C# - 예스24

더 나은 C# 코드를 작성하는 새로운 방법 50가지 C#은 전통적인 .NET 기반 개발에서 유니티 게임 엔진으로 개발 영역을 확대하면서 더욱 주목받고 있다. 또한 자마린으로 다양한 모바일 플랫폼에

댓글