ITEM 8 :: EFFECTIVE C#


안녕하세요, 8번째 시간입니다. 8은 중국에서 행운의 숫자라고 하죠?


이번 챕터에도 역시 C#에서의 새로운 연산자가 나옵니다! 새로운 걸 접하는 것은 언제나 어렵지만 재미도 있는 법이지요. 나만 그런가? 이번에 설명드릴 연산자는 C# 6.0에 새롭게 추가된 Null 조건 연산자라는 것입니다. 이걸 어디에 쓰냐, 하면, 과거의 이야기를 조금 해야합니다. 자, 설명 들어가겠습니다.

설명

  1. null 조건 연산자가 없을 때, 과거에는 null check 방식을 사용했다. 방식이라고 하면 거창하고, 단순하게 이벤트 호출전에 널을 검사했다는 것이다.
  2. 검사한 이유는 이벤트 핸들러를 통해 이벤트를 호출 할 때 넘겨받은 인자가 Null일 경우에는 당연히 안되기 때문에 검사를 하는 것이고,
  3. 추가적으로 다른 스레드에서 값을 넘기고 나서 이벤트 핸들러를 취소할 경우 NullReferenceException이 발생하므로, 이러한 Check 방식이 필요하다!

그래서 나온 null 조건 연산자

  1. 이를 사용하면, 다른 스레드에서 값을 넘기고 나서 이벤트 핸들러를 취소하더라도, 이미 널 검사를 조건 연산자가 해주기 때문에, 예외가 발생하지 않는다.
  2. 가독성이 매우 좋아진다. ( 이를 사용하지않고, NullCheck를 하드코딩으로 작성할 시, 보기도 힘들고, 이벤트 호출시마다 넣어줘야 하므로 번거롭다. 이를 사용하면 한줄로 끝난다!)
  3. 사용방법은 아래의 New 주석부분을 참고하면 좋을 것 같다. (? 연산자가 바로 Null 조건 연산자이다. Invoke는 접근하고자 하는 윈도우의 쓰레드가 아닌, 다른 쓰레드에서 이 윈도우에 접근을 시도할 때, 에러를 발생시키는데, 이 에러를 없앨 때 사용하는 함수이다.)
// 구식적인 방법. Updated가 null이 아니여서 if 구문에 들어올때,
// 다른 스레드에서 이벤트 핸들러를 취소할경우 NullReferenceException이 발생.
public void RaiseUpdates()
{
        counter++;
        if(Updated != null)
            Updated(this, counter);
}
 
// NEW!: null 조건 연산자를 이용하면 멀티스레딩 환경에도 안전하다.
public void RaiseUpdates()
{
        counter++;
        Updated?.Invoke(this, counter); // 함수를 Invoke를 통해 불렀을 때, Null이 발생할 경우 ? 조건연산자에 의해 해당 절은 무시되고 다음절로 넘어가게된다.
}

정리

멀티 스레딩 상황이나, 이벤트 핸들러 호출부분의 Null Check를 할 때 지저분한 코드를 계속해서 복사해 사용하는 것 보다, 이 방식을 사용하면 한줄로 대부분이 정리된다. 이전부터 있었던 문제인 탓에 예전 방식으로 해결된 해결책들이 인터넷에는 굉장히 많을 것으로 생각된다. 하지만, 그럼에도 구식의 것보다는 이 널 조건연산자를 사용하는 것이 명확하고 가독성이 좋으며, 예외처리에 완벽하므로 이것을 사용하는 것이 좋다!