티스토리 뷰

C#

C# 6.0 신규 기능 살펴보기

hwigyeom 2015. 11. 18. 14:19

C# 6.0은 이전 C#의 업데이트처럼 하나의 주요 기능에 초점을 맞추고 있는 것이 아니라 이전 버전에는 포함되지 않았던 작은 개선사항들이 포함되어 있습니다.
그런 면에서 본다면 메이저 업데이트라기 보다는 마이너 업데이트에 가까운 것이 아닌가 합니다만, 이번에 컴파일러(Roslyn)가 완전히 변경되었으므로 C# 6.0으로 나온 듯 합니다.

새로 추가된 사항들은 C# 언어로 코딩 하는데 있어 코드가 좀더 간결해지고 가독성이 높아지도록 하여 예외 발생 가능성을 줄이는데 목표가 있지 않나 싶습니다.
신규로 추가된 기능들은 대부분이 클래스 멤버의 선언 및 구문의 표현에 관련된 내용입니다.
그럼 하나씩 살펴 보시죠.

nameof 연산자

nameof 연산자는 연산자에 할당된 속성이나 변수의 이름을 컴파일 시 문자열로 변경해주는 역할을 합니다.
얼핏 생각하면 아무런 효용성도 없는 기능처럼 보일 수도 있습니다. nameof(Field) 로 하는 것 보다는 "Field" 라고 적는 게 더 직관적일 수 있어 보이니깐요.
하지만 아래 예제를 한번 보시죠.

위 코드처럼 파라미터로 전달된 값이 null등의 유효하지 않은 값이 전달된 경우 ArgumentException 이나 ArgumentNullException을 발생시키는 경우가 자주 있습니다.
그런데 일정 시간이 지난 후 appendString 이라는 파라미터의 이름을 appStr 로 변경한다면, ArgumentException 생성자에 전달하는 파라미터 이름 문자열도 변경해주어야 하지만, 쉽게 놓칠수 있는 부분이기도 하지요.

Visual Studio 에서 제공하는 리팩터링 기능을 이용(appendString 을 appStr로 변경 후 Shift + Alt + F10)한다면 변수로 사용되는 부분을 일괄적으로 변경이 가능해 유용하지만, 문자열로 되어 있는 ArgumentNullException의 생성자 부분은 자동으로 변경해주지 못합니다.

하지만, 아래와 같이 nameof 키워드를 이용하여 코드를 작성하고, 리팩터링 기능을 이용하면

ArgumentNullException 생성자에서도 변수를 이용하므로 변경 대상에 포함됩니다. 이 부분은 컴파일 시 문자열로 변경되니 실질적인 코드는 문자열로 지정했을 때와 동일합니다.
짧은 코드보다는 길고 복잡한 코드에서 변수나 속성의 이름을 변경 시 주의 부족으로 누락할 수 있는 부분을 깨끗하게 처리해줄 수 있는 유용한 기능입니다.

null 조건부 연산자

변수의 형식이 참조 형식일 때 인스턴스가 초기화하지 않은 상태의 변수는 null 값을 가집니다. null 값을 가지고 있는 변수를 사용하려 들면 개발자들이 가장 자주 만나는 런타임 예외 중의 하나인 NullReferenceException을 만나게 되죠. 방지하는 방법은 null 검사를 수행하는 방어적인 코딩을 하는 것입니다. 문제는 null 검사를 수행하는 단순한 코드가 계속 중복적으로 나오게 되는 점이죠.

방어적인 코드로 런타임 시 발생할 수 있는 오류를 최소화할 수는 있지만, null 체크를 위해서 코드가 길어지다 보니 핵심 코드를 파악하기가 쉽지 않아 지는 문제점이 있습니다.

C# 6.0에서는 null 조건부 연산자(?. 또는 ?[)를 통해서 null 체크가 가능합니다. ?.는 멤버에 액세스 하기 전에 수행하고, ?[는 인덱스 작업을 수행하기 전에 수행합니다.
null 조건부 연산자 좌측의 항목이 null 일 경우 null 조건부 연산자 좌측의 코드를 실행하지 않고 null을 반환합니다.
그리고 여러 개의 null 조건부 연산자를 중첩적으로 사용할 수도 있습니다. 다수의 null 체크를 한 줄에 표현할 수 도 있습니다.
Null 조건부 연산자를 이용한다면 위 코드는 아래와 같이 간단하게 표현이 가능해 집니다.

ComicBook이 null 이라면 뒤의 내용은 실행하지 않고 null을 반환하며, Images 컬렉션이 null 일 경우에도 인덱스를 이용한 접근은 실행하지 않고 null을 반환하게 됩니다.
null 병합 연산자(??)는 이전 버전의 C#에서도 사용할 수 있던 것으로 연산자 좌측 피 연산자가 null이 아닐 경우에는 좌측 피 연산자를 반환하고, 연산자 좌측 피연산자가 null 일 경우 연산자 우측 피연산자를 결과로 반환하는 것으로 null 조건부 연산자와 함께 사용하면 상당히 코드를 간결하게 만들 수 있습니다.

문자열 보간

문자열의 특정 위치에 지정한 단어 또는 문장을 삽입하여 문장을 완성시키는 일은 개발 시 정말 자주 만나게 되는 이슈 중 하나입니다.
이제까지 C#에서는 string.format 함수를 이용하거나 문자열 병합을 이용하여 이 같은 문제를 해결해 왔습니다.

string.format 함수를 이용하는 방법은 인덱스를 이용하므로 중간에 삽입해야 하는 문자열이 추가되거나 할 경우 인덱스를 조정해야 합니다. 물론, 인덱스를 조정하지 않고 사용할 수도 있겠지만, 유지보수성이 나빠지게 됩니다.

문자열 보간을 이용하게 되면 변수명을 포맷 문자열에 바로 활용하므로 문자열 작업을 아주 직관적으로 수행할 수 있습니다.

문자열 보간에는 각 형식에 맞는 형식 문자일 뿐만 아니라 보간식 내에 조건식을 추가할 수도 있습니다.

문자열 보간을 사용하고자 하는 문자열은 $ 문자로 시작해야 합니다.

자동 속성의 향상

C# 3.0 이전에는 클래스에 멤버 변수를 선언하고 캡슐화를 위해서 그 멤버 변수를 노출하는 getter 와 setter 속성을 따로 만들어줘야 하던 코드가 C# 3.0에서 컴파일 시에 내부에서 자동으로 멤버 변수를 선언하도록 해주는 자동 속성(자동 구현 속성)이 추가되면서 단순한 속성 추가를 위한 코드의 양이 상당히 많이 줄어들었습니다.

이런 코드가 자동 속성을 이용하게 되면 아래와 같이 간결해집니다.

자동 속성을 이용하다 보면 아쉬운 점이 자동 속성에 초기값까지 한번에 할당할 수 있었으면 좋겠다는 거였습니다.
초기화를 위해서는 생성자에서 속성에 초기값을 설정하거나 예전 방식으로 멤버 변수와 속성을 따로 구현해야 했었죠.

이번 C# 6.0에서는 자동 속성에 바로 값을 할당하여 초기화하는 것이 가능해 졌습니다.

그리고, 또 다른 추가 기능은 getter 하나만 존재하는 자동 속성이 생겼다는 것입니다.
외부에서 getter 에만 접근이 가능하고 setter에 접근을 하지 못하는 자동 속성을 만들 때 이전에는 setter 를 private 등의 접근 제한자를 이용해서 노출 범위를 지정하여 사용했었습니다. 하지만, C# 6.0부터는 getter 하나만 존재하는 자동 속성을 만드는 것이 가능해진 겁니다.

위 코드를 보면 Key 속성이 getter 만 지정되어 있습니다. 그리고 Update 속성은 setter가 private으로 설정되어 있죠.
두 가지 코드의 다른 점은 무엇일까요?
getter 만 있는 자동 속성은 컴파일 시 생성자를 제외한 다른 모든 위치에서 값의 변경이 불가능한 readonly로 멤버 변수가 선언되는 겁니다.
즉, private setter가 있는 Update속성은 클래스 내부에서는 언제든 값의 수정이 가능하지만 getter 만 있는 Key는 생성자가 호출되어 객체가 초기화된 이후에는 어느 코드에서도 값을 설정하거나 변경할 수 없는 것입니다.

catch 와 finally 블록에서 await 지원

C# 5.0에서 추가된 async 와 await덕분에 비동기 개발이 아주 쉬워졌습니다. 컴파일러가 개발자 대신 각 비동기 메서드의 callback 메서드의 생성과 호출을 관리해 주는 덕분에 하나의 async 메서드 내부에서 다양한 비동기 메서드의 호출을 마치 동기 방식의 코드처럼 사용할 수 있게 되었습니다.

하지만, 불행히도 이제까지는 catch 와 finally 블록 내부에서는 await 키워드를 지원하지 않았습니다. 그래서 아래와 같이 catch 나 finally 외부에서 처리하는 방식을 사용해야만 했었습니다.

C# 6.0부터는 catch 나 finally 블록 내부에서도 await 키워드의 사용이 가능해졌습니다. 위 코드는 아래처럼 catch 블록 내에서 await처리가 가능해져 예외 정보를 try-catch 블록 외부로 가지고 나와서 처리할 필요 없이 catch 블록 내에서 처리가 가능해 졌습니다.

예외 필터

이번에 살펴볼 내용은 예외 필터입니다. 예외 필터는 Visual Basic 이나 F# 등의 언어에서는 이미 지원하고 있던 기능이었지만 C#에서는 지원되지 않았던 기능이었는데 C# 6.0에서 드디어 지원하게 되었습니다.

기존에는 발생한 예외의 속성 값에 따라 다르게 예외 처리하려면 해당하는 예외의 형식을 catch 조건으로 사용하고 catch 블록 내에서 속성 값을 비교하여 처리해야 했지만, 이제는 catch 조건에서 속성 값까지 필터링하는 것이 가능해졌습니다.

위 코드는 try 블록 내부에서 ArgumentException형식의 예외가 발생하였을 때 예외의 ParamName 속성의 값이 date 일 때만 catch 블록에서 처리하고, 그 외의 경우에는 예외가 계속 전파되도록 하는 코드입니다.
이 코드를 기존 방식으로 코딩을 한다면 아래와 같이 될 것입니다.

필터 조건 절이 복잡하다면 메서드를 활용할 수 도 있습니다. 이때는 필터 조건 메서드에서 true 를 반환하면 catch 블록 내로 진입하며, false를 반환할 경우 블록 내로 진입하지 않습니다.

Using static

특정 형식의 정적 멤버를 사용할 때 형식 명을 지정하지 않아도 바로 정적 메서드에 접근할 수 있도록 해주는 것이 Using static 입니다.
C# 에서 using 은 해당 파일 내에서 사용할 형식들의 네임스페이스 명을 생략할 수 있도록 해주는 기능인데 반해, using static은 특정 클래스의 정적 메서드를 클래스 명을 생략하고 사용할 수 있도록 해주는 기능입니다. 그러므로, using static 뒤에는 네임스페이스가 아닌 클래스 명이 와야 하야합니다.

위 코드인 두 가지 메서드의 내용은 동일합니다. 위쪽 메서드에서는 using static 을 이용하여 Math 클래스의 정적 메서드인 Pow 와 정적 속성인 PI를 현재 클래스 내부에 있는 것처럼 사용하고 있는 것을 볼 수 있습니다.

인덱스 초기화

객체나 컬렉션을 선언적으로 초기화하는 방법은 상당히 유용한 C#의 기능 중 하나입니다. 선언적 초기화 방법 중 Dictionary 초기화 방법은 어떻게 보면 Dictionary의 사용방법과는 좀 상이한 방식으로 해야 했습니다.
아래는 이전에 사용하던 Dictionary 초기화 방법입니다.

인덱서로 접근하여 사용하는 Dictionary의 사용 방식과도 다르고 JSON 형식과도 좀 다릅니다.
아래는 C# 6.0에서 새로 추가된 방법입니다.

새로운 방법은 Dictionary를 사용하는 방식과 유사하여 기존 방식보다는 더 직관적이고 우아한 방법이지 않을까 싶습니다.
이 새로운 방식은 Dictionary뿐만이 아니라 키를 이용하여 값에 접근하는 인덱서가 존재하는 컬렉션 방식에는 모두 적용할 수 있습니다.

람다식을 이용한 함수 구현(Expression-bodied function members)

이제 간단한 로직을 가진 함수의 경우 람다식을 이용하여 간결하게 표현할 수 있게 되었습니다.

위 코드에서 Name 은 속성의 getter를 람다식으로 구현한 것이며, 아래는 함수를 람다식으로 구현한 것입니다.
이 방식은 연산자나 오버로딩에서도 동일하게 적용됩니다.

마치며

개발 언어는 그 언어를 이용하는 개발자들의 요구에 의해서 계속 발전해 갈 수 밖에 없습니다.
C# 언어가 처음 나왔을 때는 저는 너무 엄격하다 할 만큼 형식을 명기하는 것을 중요시 한다고 생각했던 기억이 있습니다. 하지만, C# 3.0 에 암시적 형식인 var가 추가된 이후에는 컴파일러가 너무 많은 걸 알아서 해줘서 C# 을 새로 배우는 사람들에게는 자신이 사용하는 인스턴스가 실제로는 어떤 클래스가 인스턴스화 된 건지 생각해보는 기회마저 빼앗아 가는 거 같아서 과연 좋은 것인가 하는 생각도 했었답니다.

이처럼 보는 관점에 따라서는 언어의 새로운 기능들은 양면성을 가진다고 생각합니다.
새로운 기능과 기술을 개발에 적용하는 건 상당히 권장할 만한 일이지만, 그 이전에 전제되어야 하는 건 현업에 적용할 때는 구성원들과 충분한 논의를 거쳐 합의가 이뤄진 이후에 적용해야 하는 거라고 생각합니다. 이렇게 쓰고 보니 새로운 기술을 쓰지 말라고 하는 것 같은데 그건 아니라는 거 다들 잘 알고 계시죠?

그럼 다음에 뵙겠습니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함