C# 전처리기 구문 어떻게들 사용하고 계신가요?

사실 어떻게들 쓰고 계신지 보다는 어떻게 리팩토링해서 사용하는 지가 궁금합니다. ?ㅅ?

제가 직접 처음부터 C# 으로 개발하는 프로젝트에서는
딱히 전처리기 구문이 필요한 경우가 거의 없긴 했는데…

이직하고 나서 만났던 코드들 중에
이전 작업자가 온갖 전처리기 상수를 정의해서
#if #elif #else 블럭에 허우적 대 본 경험이 있어서요.

그래도 DEBUG / RELEASE 정도는 나름 쓸모가 있다고 생각은 하는데
이것도 사실 #if 어쩌고 하면서 들여쓰기 깨는 거 자체를 저는 약간… 꼴보기 싫거든요… ~ㅅ~;;

좀 극단적인 표현이지만 예를 살짝만 들어보자면

   var list = new [] { "a", "b", "c" };
   foreach(var chr in list)
   {	
#if DEBUG
   	Console.WriteLine(chr);
   }
#else
   	Console.WriteLine(chr);
   }
#endif	

요딴식으루 작성되어 있는 걸 많이 봐 왔어요. (예를 들어서 저렇다는 겁니다… -ㅅ-;; )

그나마 DEBUG / RELEASE 정도야 그렇다치는데
위 예처럼 중괄호 블럭을 애매하게 포함시킨다든가 하는 경우도 많았고
(그래서 빌드 설정이 바뀌면 당장 빨간불이 죽죽…)

저렇게 코드 진행 중에 들여쓰기를 깨는 듯한 것들만 보면 좀 짜증이 밀려오기도 하구요…;;
(실제로 가독성을 해치기도 하구요…)

그래서 저는 저런 걸 만나면 메서드로 다 분리해서 Conditional 처리해버리는데

[Conditional("DEBUG")]
private void StartByDebug(string chr)
{
	Console.WriteLine(chr);
}

[Conditional("Release")]
private void Start(string chr)
{
	Console.WriteLine(chr);
}

var list = new [] { "a", "b", "c" };
foreach(var chr in list)
{
	StartByDebug(chr);
	
	Start(chr);
}

사실 이것두 깔끔하지 않은 건 마찬가지인 거 같습니다.

게다가 메서드로 분리하면 호출하는 위치에서는 저게 두 번 호출되는 거 같은 느낌이라서요.

다른 전처리기 구문은 잘 모르겠고 (아, 생각도 하기 싫… ;;; )
DEBUG / RELEASE 정도로 나눠서 분기되는 코드를 만든다고 친다면

다들 어떤 식으로 사용하시나요?

깔끔하게 ?ㅅ?

음…
그럼 이거 약간 범위를 좁혀서 #if DEBUG 정도만 얘기해보면 어떨까요?

예시처럼
다들 그냥 코드 중에

#if DEBUG
   	Console.WriteLine(chr);
   }
#else
   	Console.WriteLine(chr);
   }
#endif	

요렇게 쓰시나요?
아니면 이것도 정리해서 다른 방식으로 쓰실까여?ㅅ?

아… 저는 코드 중간에 #if #endif 나오는 걸 좀 피라고 싶셉습니다… ;ㅅ;

  • 참고로 테스트하면서 안 사실인데…

LINQPad 는 DEBUG 로 실행되는 것이었군요… 0ㅁ0!

좋아요 1

저는 #region 말고는 안쓰는 것 같아요 :thinking:

좋아요 2

실행환경설정이라던가 로그기록 정도가 #if로 분기할 만한 내용인데요. 저도 거의 안써서 의미있는 답을 못하고 눈팅만 하고 있었습니다.

이외에 전처리문을 써야하는 경우가 무엇이 있을까요?

좋아요 1

저 같은 경우는 실수로 Debug 구성으로 사원들이 빌드해서 배포하지 않도록 빌드된 어플리케이션이 Release인지 Debug인지 UI에 띄워주려고 사용합니다…

좋아요 1

저도 개인적으로는 그러한데

이게 네이티브 개발하시던 분 습관인지는 모르겠는데
솔루션 수준에서 분리되어야하는 것들인데
이걸 한 어셈블리에서 코드로 분리 처리하면서 많이 섞어 놓았더라구요.

예를 들면 전처리기에다가 CEF 뭐 이런 거 정의해놓고

#if _CEF_
   chrome.Navigate(); 
#else
   gmap.Navigate();
#endif

(간단히 쓴겁니다…)

=ㅅ=;;

뭐 이런식으로 쓰더라구요.
(대략 #if #else저 구문 안으로 한 1200 줄 정도 코드를 만들어놨더군요. 중복된 코드들을 덕지덕지…)

개인적으로는
이걸 이렇게 써야할 일인가… +ㅁ+! 하면서 수정하는 데 엄청 애먹었죠.

뭐 이건 극단적인 경험(!) 이긴 한데
#if DEBUG 정도는 쓸 수 있겠다는 생각을 하긴 합니다.
그런데 이것도 #if 코드를 실행 흐름 중에 만나는 게 너무 짜증나거든요.
(그래서 [Conditional()] 로 처리하긴 하는데…)

좀 깔끔한 방법을 찾고 싶어서 여쭤봤어요… ;ㅅ;

음… 혹시

그러면 이런 경우는 어떻게 처리하시는 가요?

예를 들면
같은 분기에서 DEBUG 에서 파일에 로그를 쓰고 RELEASE 에서는 Email 을 보내는 상황에서

#if DEBUG
   Logger.Log(message);
#else
   mailRepo.Send(message);
#endif

이런 식이 될 텐데

그냥 이런 식으로 로그를 쓰는 위치에서 #if 로 처리를 하시는 편인가요?

[Conditional()] 로 처리해도 같은 위치에서 코드 상으로 두번 호출하는 것처럼 작성해야해서
그것도 좀 보기 불편한 거 같거든요.

왠만하면 전처리문은 사용 안하는쪽으로 코딩을 해야죠.
전처리문을 사용하는 이유가 대부분 디버깅시 로그 출력이고, 그외에 조건에 따른 기능 변경인데, 이런건 IDE 디버깅이나 NLOG, CONFIG 파일등으로 대체할 수 있기 때문에 굳이 사용할 이유가 없습니다.
그래도 꼭 전처리문을 사용해야한다면 차라리 분기를 따로 만들어서 관리하는데 더 나을 수 있겠죠.

좋아요 2

c++에서도 그런용도의 전처리기 사용은 욕먹기 좋습니다.
혼자 죽을때까지 만들거 아닌 이상은 후임자가 보기 드럽거든요.
제 경우는 특별한 경우나 테스트아니면 디버그 전처리기만 사용 합니다.

위의 특별한 경우도 디버그 때문입니다.
예를들어 윈도우서비스를 만드는데. 매번 디버깅이 번거로우니
시작 부분하고 몇군데만 전처리기로 나눠서 WIndowsForms로 실행되게 한적이 있습니다.
이것도 디버그 전처리기로 가능은 하지만 그때 사용한 API들이 윈도우서비스랑 윈폼에서 아예 따로 노는것들이
있어서 빌드 설정에 Debug_WinForm, Release_WinForm 을 만들었죠.
현재는 서비스는 와치독 형태로 실행되는 프로그램의 감시 및 문제 발생 시 재실행만 하도록 수정했습니다.

좋아요 2