
숫자 값의 부호를 변경하고 싶을 때 단항 빼기 연산자(-)를 사용한다.
이항 연산자에는 피연산자가 두 개 필요하다. 중위 표기법으로 이항 연산자를 나타낸다. 이항 연산자는 왼편 피연산자와 오른편 피연산자 사이에 나타난다. 연산자의 우선순위로는 *, /, % 가 가장 높고 그다음은 +, -이고 =가 가장 낮은 우선순위를 갖는다.
char 형식을 소개할 때 숫자가 아닌 문자를 저장하더라도 char 형식은 정수 계열 형식이라고 언급했다. 이 형식은 다른 정수 형식과 산술 연산에 참여할 수 있다. 하지만 char 형식의 값이라는 해석에 따르면 그 안에 저장된 문자를 기반으로 하지 않고 내부 값을 기준으로 한다.
내부적으로 2진 부동소수점 형식은 실제 소수가 아니라 2진 소수를 저장한다. 이는 double number = 140.6F처럼 부정확한 표현오류가 단순 할당에서 발생할 수 있다는 의미다. 140.6의 정확한 값은 분수 703/5이지만, 이 분수의 분모는 2의 거듭제곱이 아니므로 2진 부동 소수점 수로 정확히 표현할 수 없다.
부동소수점 수는 예상치 못하게 소수로 반올림이 일어날 수 있기 때문에 부동소수점 값의 등가성을 비교하면 상당한 혼란을 겪게 된다. 기타 고유한 부동소수점의 특징은 0으로 정수를 나누면 에러가 발생이 예상되는데, 이는 int와 decimal 같은 데이터 형식에서 일어난다. 하지만 float과 double 형식에서는 에러를 일으키지 않고 특정 값을 나타낸다.
부동소수점 수 역시 범위 초과로 인한 오버플로가 발생할 수 있다. 예를 들어 float형식의 상한 값은 대략 3.410^38 정도가 된다. 숫자가 이 범위를 넘어간다면 결과는 '양의 무한대'로 저장되고 이 숫자의 출력은 Infinity다. 마찬가지로 float 형식의 하한 값은 -3.410^38이고 범위를 벗어나는 값을 계산하면 '음의 무한대'가 돼 문자열 -Infinity로 표시한다. 부동소수점 수를 좀 더 확인해 보면 실제로는 0을 포함하지 않고 0에 매우 가까운 값을 포함할 수 있다. 값이 float이나 double 형식에 대한 하한 임계값을 초과한다면 숫자의 값은 숫자가 음수인지 양수인지에 따라 '음의 0'이나 '양의 0'으로 표시되는데, 출력 내역에는 각기 -0이나 0으로 표시된다.
복합 할당 연산자는 할당 연산과 일반적인 이항 연산을 결합하는 역할을 한다. += 연산자는 해당 연산자의 오른편 값으로 연산자의 왼편 변수를 증가시킨다.
C#에서는 증가 및 감소 카운터로 쓸만한 특수한 단항 연산자가 있다. 증가 연산자 ++은 사용될 떄마다 변수를 1씩 증가시킨다.
증가와 감소 연산자는 코드를 간결하게 하지만, 이들 연산자는 원자성이 없다. 이 연산자를 실행하는 동안 스레드 콘텍스트 전환이 발생할 수 있고 경합 상태를 유발 할 수 있다. lock 구문을 사용해 이런 경합 상태를 차단한다. 하지만 간단한 증가와 감소의 경우 비용이 덜 드는 대안으로 System.Threading.Interlocked에 속한 스레드로부터 안전한 Increment()와 Decrement()를 사용하면 된다.
const 키워드로 지역 상수를 선언한다. 지역 상수는 변수의 반대 개념으로 정의되므로, 나중에 나오는 코드에서 이 값을 수정하려는 시도를 하게 되면 컴파일 타임 에러가 발생한다.
if문은 C#에서 가장 일반적인 구문 중 하나다. 이 문은 조건이라는 부울식을 평가한다. 조건이 참이면 후속 문이 실행된다. if문은 선택적으로 대안문을 포함하는 else절을 가질 수 있고 이 절은 조건이 거짓인 경우 실행한다.
코드에 여러개의 if문이 필요할때가 있으면 사용하는것으로 if문 안에 if문이 들어간다.
중괄호 사용으로 여러 줄의 구문을 단일 구문으로 결합할 수 있는데, 이를 블록문 또는 코드 블록이라 하고, 여러 구문을 하나의 구문으로 다룰 수 있다.
코드 불록을 종종 '범위'라고 하지만, 두 가지 용어가 정확히 같은 의미는 아니다. 이름을 부여한 요소의 범위는 그 요소의 비정규화된 이름으로 해당 요소를 참조해도 되는 소스코드의 영역이다. 지역 변수의 범위는 정확히 그 변수를 감싸는 코드 블록의 텍스트이므로, 일반적으로 코드 블록을 '범위'라고 하는 이유이기도 하다.
범위를 종종 선언 공간과 혼동하기도 한다. 선언 공간은 이름을 부여한 요소들의 논리 컨테이너로 여기서는 두 가지가 동일한 이름을 갖기 않을 수 있다. 코드 블록은 범위를 정의할 뿐만 아니라 지역 변수 선언 공간도 정의한다. 같은 이름을 가진 두 개의 지역 변수 선언이 동일한 선언 공간에 나타나면 안 된다. 같은 이름을 가진 두 개의 지역 변수 선언이 동일한 선선 공간에 나타나면 안 된다. 마찬가지로 동일한 클래스 내에 Main()이라는 시그니처를 갖는 두 개의 메소드도 선언할 수 없다. 블록 내에서 지역 변수는 이름으로 언급할 수 있으며, 블록에서 그 이름은 고유한 요소로 선언해야 한다. 블록 선언 외부에서 이름으로 지역을 참조할 방법이 없다. 해당 블록 외부인이 지역을 '범위 밖'이라고 한다.
요약하면 범위는 이름이 참조하는 대상을 결정하는 데 사용되고, 선언 공간은 동일한 이름으로 선언된 두 가지가 언제 서로 충돌하는지를 결정한다.
부울식은 대부분의 흐름 제어 구문내에서 나타난다. 핵심 특징은 항상 참이나 거짓으로 평가한단는 점이다.
관계 연산자와 같음 연산자는 한 값이 다른 값보다 큰진나 작은지 또는 같은지를 결정한다. 이들 모두는 이항 연산자다. C# 문법에서 같음을 나탄낼 때는 다른 많은 프로그래밍 언어처럼 ==를 사용한다. 같음 연산자는 두 개의 같음 기호를 사용해서 할당 연산자 =와 구별한다. 감탄 부호는 C#에서 NOT을 의미하므로 같지 않음을 시험하려면 같지 않음을 나타내는 연산자인 !=를 사용한다.
논리 연산자는 부울 피연산자를 취하며, 결과는 부울 값이다. 논리 연산자를 사용하면 다수의 부울식을 결합해 더 복잡한 부울식을 구성할 수 있다. 논리 연산자에는 |와 ||, &, &&, ^가 있으며, 이들은 각기 논리합(OR)과 논리곱(AND), 배타적 논리합(XOR)에 해당한다. 이 절에서 설명하는 내용 때문에 OR와 AND의 |와 & 버전은 부울 로직에서 거의 사용하지 않는다.
사용자가 두 가지 방식으로 사용을 끝내게 하려면 논리 OR 연산자 ||를 사용한다. || 연산자는 부울식을 평가하고, 결과는 피연산자가 하나라도 참이면 참이다. OR 표현식은 한쪽 피연산자의 결과가 참이면ㄴ 다른 피연산자의 결과는 볼 필요도 없이 참이 되므로 양쪽을 다 평가할 필요는 없다.
부울 AND 연산자 &&는 양쪽 피연산자가 모두 참으로 평가될 때만 참이다. 어느 한쪽 피연산자가 거짓임면 결과는 거짓이 된다. OR 연산자와 비슷하게 AND 연산자는 항상 표현식의 오른편을 평가하지는 않는다. 왼쪽 피연산자가 거짓으로 결정되면 전체 결관는 오른쪽 피연산자의 값에 상관없이 거짓이므로, 런타임에 오른쪽 피연산자의 평가를 건너뛴다.
부울 피연산자에 XOR를 적용하면 피연산자 중 하나만 정확히 참인 경우 참을 반환한다. 부울 AND 연산자나 부울 OR 연산자와는 달리 부울 XOR 연산잔는 단락이 일어나지 않는다. 양쪽 피연산자의 값을 알아야만 결과를 결정할 수 있으므로 항상 양쪽 피연산자의 값을 검사한다.
논리 부정 연산자 또는 NOT 연산자인 !는 bool 값을 반대로 바꾼다. 이 연산자는 단항 연산자로 피연산자 하나만 사용한다.
두 개의 값 중 하나를 선ㄴ택하는 데 사용된 if-else문 대신 조건 연산자를 사용할 수 있다. 조건 연산자는 물음표와 콜론 두 가지를 사용한다. 조건 ? 결과 : 대안의 형태를 가지고 있으며 조건 연산자는 조건, 후속, 대안이라는 세 개의 피연산자가 있는 '삼항' 연산자다. 논리 연산자처럼 조건 연산자는 단락 형식을 사용한다. 조건이 참이면 조건 연산자는 단락 형식을 사용한다. 조건이 참이면 조건 연산자는 후속 항만 평가한다. 조건이 거짓이면 대안 항만 평가한다. 연산자의 결과는 평가식이다.
Null 병합 연산잔는 "이 값이 null이면 이때 다른 값을 사용한다"는 것을 표현하는 간결한 방식이다. 표현식1 ?? 표현식2의 형태를 가지고 있으며 Null 병합 연산자는 단락 형식으로도 사용한다. 표현식1이 Null이 아니면 그 값이 연산의 결과이고, 다른 표현식은 평가되지 않는다. 표현식1이 Null로 평가되면 표현식2의 값은 이 연산자의 결과다. 조건 연산자와 달리 Null 병합 연산자는 이항 연산자다.
null인 값으로 메소드를 호출할 때마다 런타임에서는 System.NullReferenceException을 던져 프로그래밍 로직의 에러를 나타낸다. Null 조건 연산자는 피연산자가 메소드나 속성을 호출하기 전에 null인지 여부를 검사한다. 표현식이 체인으로 연결될 때 첫 번째 피연산자가 null이면 표현식 평가는 단락되며, 더 이상 표현식 호출 체인 내의 호출이 일어나지 않는다. 하지만 추가적인 Null 조건 연산자를 의도치 않게 무시하지 않도록 주의를 기울여야 한다. Null 조건 연산자에 관해 주목할 중요한 점은 값 형식을 반환하는 멤버로 활용할때 항상 그 형식의 Null 허용 버전을 반환한다는 것이다. 조금 색다를 수 있지만 Null 허용 값 형식은 호출 체인의 마지막에서만 생성된다.
사실상 모든 프로그래밍 언어에서 2진 형식의 값을 조작하는 데 사용하는 연산자들을 비트 연산자라고 한다.
컴퓨터 내의 모든 값은 1과 0의 2진 형식으로 나타내는데, 이를 2진수라 한다. 비트 여덟 개를 모은 것을 바이트라 한다. 바이트에서 연속하는 비트는 2의 거듭제곱의 값에 해당한다. 대부분의 시나리오, 특히 저수준 또는 시스템 서비스를 다룰 때면 정보를 2진 데이터로 얻는다. 이러한 장치와 서비스를 조작하려면 2진 데이터를 조작해야 한다. 방금 설명한 2진 변환은 부호 있는 숫자에 대해서는 상당히 다르다. 부호 있는 숫자는 '2의 보수' 표기를 사용해서 나타낸다. 2의 보수 표기는 양수에 음ㅁ수를 더할 때 양쪽이 양수 피연산자인 것처럼 덧셈이 계속 동작하게 하는 것이다. 이 표기법을 사용하면 음수는 양수와 다르게 동작한다. 음수는 맨 왼쪽 위치에 1을 넣어 구분한다. 맨 왼ㄴ쪽 위치에 1이 있다면 1인 위치보다는 0인 위치를 더한다. 0인 위치에서 2의 제곱을 구하고 음수로 표시한다. 거기다가 결과에서 1을 다시 빼야 한다.
어떤 숫자의 2진 값을 오른쪽이나 왼쪽으로 이동해야 할 때가 종종 있다. 왼쪽 시프트 실행에서 숫자를 2진수로 표현한 모든 비트는 시프트 연산자의 오른편에 지정한 위치 숫자만큼 왼쪽으로 이동된다. 이때 2진수의 오른편 위치에서 뒤를 메우는 데 0을 사용한다. 오른쪽 시프트 연산자는 반대 방향으로 동일한 동작을 한다. 하지만 숫자가 부호 있는 형식의 음수라면 2진수의 왼편을 뒤에서 메우는 데 사용되는 값은 1이며 0이 아니다. 시프트 연산자는 >>와 <<이며 이들은ㄴ 각기 오른쪽 시프트 및 왼쪽 시프트 연산자라 한다. 게다가 시프트 연산자와 할당 연산자를 결합해 <<=와 >>=로 사용할 수 있다.
가끔 피연산자 두 개에 대한 비트 단위로 AND, OR, XOR 같은 논리 연산을 수행해야 할 경우가 있따. 이런 연산을 &와 |, ^ 연산자로 수행한다.
숫자 두 개를 갖고 있다면 비트 연산에서는 최상위 값에서 시작해 끝에 이를 때까지 오른쪽으로 계속 진행하면서 해당 위치의 값을 비교한다. 해당 위치에 1이라는 값은 참, 0이라는 값은 거짓으로 처리한다.
&=, |=, ^=처럼 이들 비트 연산자와 할당 연산자를 결합할 수 있다. 이 결합의 결과는 변수와 숫자의 OR 연산을 하고, 그 결과를 다시 원래 변수에 대입한다.
비트 보수 연산자는 피연산자의 각 비트의 보수를 취하는데, 여기서 피연산자는 int나 uint, long, ulon이다. 그러므로 ~1은 이진수 표기로 1111 1111 1111 1111 1111 1111 1111 1110인 값을 반환하고 ~(1<<31)은 2진수 표기로 0111 1111 1111 1111 1111 1111 1111 1111인 숫자를 반환한다.
while문은 while (조건) 구문의 구조를 가지며 컴퓨터는 조건이 참으로 평가되는 동안 루프의 '본문'인 구문을 반복적으로 실행한다. 조건이 거짓으로 평가되면 코드 실행에서 본문을 건너뛰고 루프구문 다음의 코드를 실행한다. 구문에서 조건을 거짓으로 만들더라도 해당 구문은 실행된다. '루프의 맨 처음'에서 조건이 재평가될 때만 루프를 빠져나간다.
'루프 본문'이라는 용어는 while문 내에서 실행될 해당 구문을 의미하는데, 이는 해당 코드가 종료 조건을 얻을 때까지 '루프"에서 실행되기 때문이다. 어떤 루프 구조를 선택할지 이해하는 것이 중요하다. 해당 조건이 참인 동안 while 구문을 반복한다. for 루프는 0에서 n까지 세는 것처럼 반복 횟수를 알고 있는 경우 가장 적합한 수단이다. do/while은 while 루프와 비슷하지만, 최초 한 번은 루프 본문이 항상 실행된다는 점이 다르다. do/while 루프는 while 루프와 아주 비슷하지만, do/while 루프의 경우는 반복 횟수가 1에서 n까지이면서 반복을 시작할 때 n을 모르는 경우 주로 사용한다. 이 패턴은 사용자에게 입력을 요청할 때 자주 발생한다.
do
구문
while(조건);
모든 흐름 제어 구문에서처럼 통상 여러 구문이 루프 본문으로 실행되도록 코드 블록이 단일 구문으로 사용된다. 하지만 레이블 구문이나 지역 변수 선언을 제외하고 모든 단일 구문을 사용할 수 있다.
for 루프는 지정한 조건에 도달할 때까지 코드 블록을 반복한다. 이런 방식은 while 루프와 상당히 유사하다. 차이점이라면 for 루프에는 루프 변수라는 카운터의 값을 초기화하고 증가시키며 검사하는 내장 구문이 있다. 증가 연산을 위한 루프 구문의 특정 위치가 있기 때문에 종종 증가와 감소 연산자가 for 루프의 일부로 사용된다. for 루프 헤더의 세 부분에서 먼저 count 변수를 선언하고 초기화한 후에 루프 본문이 실행될 조건을 기술한 다음, 마지막으로 루프 변수를 업데이트하는 작업을 작성한다. for 루프의 일반적인 형식은 다음과 같다.
for (초기식; 조건식; 루프)
구문
'초기식' 부분은 첫 번째 반복에 앞서 작업을 수행한다. 변수를 선언하고 초기화한다. 초기식에서 새로운 변수를 선언하는 것은 삼가야 한다.
'조건식' 부분은 종료 조건을 지정한다. while 루프처럼 이 조건이 정확히 false가 될 때 루프를 벗어난다. for 루프는 조건이 참으로 평가되는 동안만 본문을 실행한다.
'루프' 표현식은 각 반복 이후에 실행된다.
'구문' 부분은 '루프 본문'에 있는 코드이며, 조건식이 참인 동안 실행된다.
foreach 루프는 항목의 컬렉션을 반복하며 루프 변수를 설정해 각 항목을 차례로 나타낸다. 루프의 본문에서 해당 항목에 작업을 수행한다. foreach 루프의 한 가지 멋진 속성은 모든 항목이 정확히 한 번만 반복되는 것이다. 다른 루프에서 발생할 수 있는 것처럼 해당 컬렉션의 마지막을 잘못 세거나 반복을 지나칠 가능성은 없다.
foreach(형식 변수 in 컬렉션)
구문
'형식'은 해당 컬렉션 내에서 각 항목에 대한 변수의 데이터 형식을 선언하는 데 사용한다. var를 쓸 수 있으며, 이 형식은 해당 컬렉션의 형식에서 그 항목의 형식을 유추한다.
'변수'는 foreach 루프에서 컬렉션 내의 다음 항목을 자동으로 할당하는 읽기 전용 변수다. 이 변수의 범위는 해당 루프의 본문으로 제한된다.
다른 상수 값과 비교해야 하는 값을 갖는 경우 switch문에서 복잡한 if문을 더 쉽게 한다. switch문은 다음과 같은 형식이다.
switch(표현식)
{
case 상수:
구문
default:
구문
}
'표현식'은 다른 상수와 비교하는 값이다. 이 표현식의 형식으로 switch의 '관련 형식'을 결정한다. 사용할 수 있는 관련 데이터 형식은 bool, sbyte, byte, short, ushort, int, uint, long, ulong, char, 그리고 모든 enum 형식, 이들 각 값 형식의 해당 null 허용 형식이다.
'상수'는 관련 형식과 호환되는 모든 상수 표현식이다.
한 개가 넘는 case 레이블이나 default 레이블의 그룹 다음에는 switch 섹션이라는 하나 이사의 구문이 온다. 앞서 패턴에는 두 개의 스위치 섹션이 있다.
'구문'은 해당 스위치 섹션의 레이블에 언급한 상수 값 중 하나와 해당 표현식이 같을 때 실행되는 하나 이상의 구문이다. 구문 그룹의 마지막 위치로 보내지 않아야 한다. 전형적으로 마지막 구문은 break나 return, goto문과 같은 점프 구문이다.
스위치 섹션이 없는 switch문은 컴파일러 경고가 발생하지만 그 구문은 컴파일된다.
스위치 섹션이 나타나는 순서는 중요하지 않다. default 섹션이 마지막에 나와야 하는 것은 아니다. 사실 default 스위치 섹션은 없어도 무방하며 선택적이다.
C# 언어에서는 마지막 섹션을 포함해 모든 스위치 섹션의 종료 지점에 도달하지 않게 해야한다. 즉, 스위치 섹션은 대개 break나 return, goto로 끝난다는 의미다.
루프의 실행 경로를 바꿀 수 있다. 사실 루프 조건이 참이더라도 점프문을 이용해 루프 밖으로 빠지거나 남은 반복을 건너뛰고 다음 반복을 시작할 수 있다.
루프나 switch문의 밖으로 나가려면 C#에서는 break문을 사용한다. break문을 만날 때마다 즉시 루프나 스위치에서 제어권이 반환된다.
루프 내에 일련의 구문을 포함하는 블록이 있는 경우가 있다. 어떤 조건에서 일부 반복의 경우 이들 구문의 일부만 실행하게 만들고자 결정한다면 continue문을 사용해 현재 반복의 끝으로 건너뛰고 다음 반복을 시작할 수 있다. continue문은 현재 반복을 빠져나가고 해당 루프 조건을 건너뛴다. 이떄 루프 조건이 여전히 참이라면 이 루프는 계속 실행된다.
초기의 프로그래밍 언어는 C#과 같은 현대 언어에서는 당연히 비교적 정교한 '구조화 된' 흐름 제어가 부족해서 필요한 흐름 제어를 간단한 조건 분기(if)와 비조건 분기(goto)에 의존했다. 이렇게 만든 프로그램은 이해하기 어려울 때가 종종 있었다. C#내에서 goto문이 계속 존재하는 것은 경험 있는 많은 프로그래머에게는 시대착오적인 것처럼 보일 수 있다. 하지만 C#에서는 switch문 내에서 제어 이동을 지원하는 유일한 방법이 goto이기 때문에 이를 지원하다. /out 옵셥이 설정되면 코드 실행은 goto문을 사용해 default 케이스로 건너뛰며, /f의 경우도 마찬가지다.
흐름 제어문은 실행 시에 표현식을 평가한다. 그에 반해 C# 전처리기는 컴파일하면서 호출된다. 전처리기 명령은 C# 컴파일러에 대한 지시문으로 컴파일할 코드 부분을 지정하거나 해당 코드 내에서 특정 에러와 경고를 처리하는 방법을 지정한다. C# 전처리기 명령은 코드의 구성과 관련해 C# 편집기에 지시문을 제공할 수도 있다. 각 전처리 지시문은 해시 기호(#)로 시작하고, 모든 전처리기 지시문을 한 줄에 표시해야 한다. 세미콜론이 아니라 새 줄 기호로 해당 지시문의 끝을 나타낸다.
#if와 #endif 전처리 지시문을 사용하면 이 줄의 코드는 전처리 기호 CSHARP2PLUS가 정의돼야만 컴파일된다. else-if 조건을 처리하려면 완전히 별개의 두 #if 블록을 생성하지 않고 #if 지시문 내에서 #elif 지시문을 사용할 수 있다.
두 가지 방식으로 전처리 기호를 정의할 수 있다. 첫번째는 #define 지시문을 사용하여 정의하는 방식이다.
#define CSHARP2PLUS
두 번째 방식은 닷넷 컴파일 시에 define 옵션을 사용한다.
>csc.exe /define:CSHARP2PLUS TicTactoe.cs
여러 개의 정의를 추가하려면 세이콜론으로 정의를 분리한다. define 컴파일러 옵션의 이점은 소스코드 변경이 전혀 필요하지 않으므로 동일한 소스 파일을 사용해 두 가지 다른 바이너리를 얻을 수 있다는 점이다.
기호의 정의를 해제하려면 #define을 사용하는 것과 동일한 방식으로 #undef 지시문을 사용한다.
종종 코드에 잠재적인 문제를 표시하고 싶을 때가 있따. #error와 #warning 지시문을 삽입해 에러와 경고를 발생시킬 수 있다. 3목 예제를 사용해 코드에서 아직은 플레이어가 동일한 이동을 여러 번 입력하지 못하게 막지 않았음을 경고하고 있다.
#warning 지시문을 포함시킴으로써 컴파일러에서 경고를 보고하게 한다. 이 특정 경고는 코드 내에 잠재적 향상이나 버그가 있다는 사실을 표시해두는 방식이다. 이는 개발자에게 보류 중인 작업을 일깨워 주는 간단한 방식이 될 수도 있다.
경고는 잠재적으로 골칫거리가 될 수 있는 코드를 가리키기 때문에 유용하다. 하지만 이들 경고를 무시하는 편이 좋을 때도 있기 때문에 명시적으로 특정 경고를 끄는 경우가 바람직할 때가 있다.
#pragma 지시문 외에 C# 컴파일러에서는 통상 nowarn: 옵션을 지원한다. 이 옵션은 소스코드에 추가하는 대신 컴파일러 옵션으로 명령을 삽입할 수 있다는 점을 제외하면 #pragma와 동일한 결과를 낸다. nowarn 옵션은 전체 컴파일에 영향을 끼치며, 반면에 #pragma 옵션은 이 옵션이 나타난 파일에만 영향을 끼친다.
#line 지시문은 C# 컴파일러에서 에러나 경고를 보고하는 줄 번호를 제어한다. 이 지시문은 대개 C# 코드를 내보내는 유틸리티와 디자이너에서 사용된다.
default가 있는 #line 지시문은 이전에 #line 지시문의 사용을 지정하지 않고 앞서 모든 #line 지시문의 효과를 제거하고 컴파일러로 하여금 실제 줄 번호를 보고하도록 지시한다.
C#은 비주얼 코드 편집기의 콘텍스트 내에서 유용한 두 개의 전처리 지시문인 #region과 #endregion을 제공한다. 마이크로소프트 비주얼 스튜디오와 같은 코드 편집기는 소스코드를 검색하고 이들 지시문을 찾아서 코드를 작성할 때 편집기 기능을 제공한다. C#에서는 #region 지시문을 사용해 코드의 영역을 선언할 수 있다. #region 지시문은 #endregion 지시문과 일치하게 쌍을 이뤄야 하며, 두 가지 지시문 다음에 선택적으로 설명 문자열을 포함할 수도 있다. 게다가 한 영역 내에서 다른 영역을 중첩할수도 있다.
