C# C++ 차이점
- C# : 완전 객체 지향 언어 → 전역변수, 전역 함수는 없다.
- static 멤버를 사용하는 것으로 바뀌었다.
- 시작점이 정해져있다. - 2가지 방법 (2개 중 하나만 써야한다.)
- 최상위문
- Main함수를 static으로 선언하는것
- include, 전방선언 다 필요없다.
- 프로젝트에 정의되어있는 클래스 등을 아무데서나 쓸 수 있다.
- 헤더파일이 없어서 한 파일 내에서 선언과 정의를 모두 해야한다.
- C#코드는 실행파일이 아니라 IL 파일이다.
- OS에서 바로 실행되기 때문이다.
- 네이티브 언어라고 부른다.
- 빌드를 플랫폼에 따라 다르게 설정할 필요가 없어진다.
- 이 실행 환경을 모든 플랫폼이 공유하는 것이다.
- CRL이라고 부른다.
- OS에서 바로 실행되기 때문이다.
선택적 매개변수와 명명된 인수
선택적 매개변수(Optional Parameters)
- 매개변수에 기본값을 지정할 수 있음
- 호출 시 생략하면 기본값이 사용됨
- 필수 매개변수가 선택적 매개변수보다 앞에 와야 함
- 즉, 선택적 매개변수는 뒤에서부터 하나씩 추가해야한다.
- int a, int b, int c, int d = 0 이런식으로 사용
//int x = 23 -> 선택적 매개변수
void Foo(int x = 23) { Console.WriteLine(x); }
Foo(); // 출력: 23 (기본값 사용)
Foo(42); // 출력: 42 (명시적 값 사용)
// 여러 개의 선택적 매개변수
void Bar(int a = 0, int b = 0, int c = 0, int d = 0) { ... }
Bar(d:3); // 특정 매개변수만 지정 가능
- d:3 → 특정 매개변수만 기본값을 지정해서 사용할 수 있다.
명명된 인수(Named Arguments)
- 매개변수를 이름으로 지정할 수 있음
- 순서와 관계없이 인수 전달 가능
- 코드의 가독성을 높여줌
void Foo(int x, int y) { Console.WriteLine($"{x}, {y}"); }
// 다양한 호출 방법
Foo(x:1, y:2); // 출력: 1, 2
Foo(y:2, x:1); // 출력: 1, 2 (순서 변경 가능)
// 위치 기반 인수와 혼합 사용
Foo(1, y:2); // 출력: 1, 2
- Foo(y:2, x:1) → 이렇게하면 매개변수의 순서가 아니라 이름으로 지정해서 값이 할당된다.
ref 지역 변수와 반환
ref 지역 변수
- 배열 요소나 필드를 참조할 수 있는 지역 변수
- 변수가 가리키는 저장소를 직접 참조함
- 특정 위치의 값이 변경될 수 있다.
int[] numbers = { 0, 1, 2, 3, 4 };
ref int numRef = ref numbers[2]; // numbers[2] 참조
numRef *= 10; // numbers[2]가 변경됨
Console.WriteLine(numRef); // 출력: 20
Console.WriteLine(numbers[2]); // 출력: 20
- ref int numRef = ref numbers[2] → 2번 인덱스를 ref 변수에 참조하려는 것이다.
- int[] numers2 = numbers; → 가능
- numbers = null;
- numers[2] = -1; → 예외가 난다.
- numbers2[2] = -1; → 예외가 나지 않는다.
- 이유 : 설 하나의 주소를 바라봤지만 numers는 null로 가리키는 주소를 삭제했다.
- ref int[] numbers2 = ref numbers; → 이렇게하면 위의 내용에서 2개 모두 에러가 난다.
- 이유 : ref는 할당하는 변수의 다른 이름이기 때문에 2개는 같은 주소로 가리키고 있는 것이다.
ref 반환
- 메서드가 변수에 대한 참조를 반환할 수 있음
- 호출자는 반환된 참조를 통해 원본을 수정할 수 있음
class Program
{
static string x = "Old Value";
static ref string GetX()
{
return ref x; // x에 대한 참조 반환
}
static void Main()
{
ref string xRef = ref GetX(); // 참조로 받음
xRef = "New Value"; // 원본 x 수정
Console.WriteLine(x); // 출력: New Value
}
}
암시적 타입 지정과 새로운 표현식
var - 암시적 타입 지정 지역 변수
- var 키워드를 사용하면 컴파일러가 타입을 추론함
- 선언과 동시에 초기화해야 함
- 한번 추론된 타입은 변경할 수 없음
- 매개변수, 매서드에서 사용할 수 없다.
- 지역변수에만 사용 가능하다.
var x = "hello"; // string으로 추론
var y = new StringBuilder(); // StringBuilder로 추론
var z = (float)Math.PI; // float로 추론
// 컴파일 오류 예제
var x = 5;
x = "hello"; // 오류: x는 int로 추론되었음
// 컴파일러가 타입을 명확히 추론할 수 없는 경우 사용 자제
Random r = new Random();
var x = r.Next(); // x의 타입이 불명확할 수 있음
대상 타입이 지정된 new 표현식
- C# 9.0부터 도입된 기능임
- 컴파일러가 타입을 명확히 추론할 수 있는 경우 new 뒤의 타입을 생략할 수 있음
// 기존 방식
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder("Test");
//var sb1 = new StringBuilder(); 이것도 가능하다.
// 대상 타입이 지정된 new 표현식
StringBuilder sb1 = new();
StringBuilder sb2 = new("Test");
// 생성자에서 특히 유용함
class Foo
{
StringBuilder sb;
public Foo(string initialValue)
{
sb = new(initialValue); // StringBuilder 타입 추론
}
}
// 메서드 호출에서도 유용함
MyMethod(new("test"));
void MyMethod(StringBuilder sb) { ... }
식의 개념
- 식(Expression)은 값을 나타내는 코드 단위임
- 가장 단순한 식은 상수와 변수임
- 연산자(Operator)를 사용하여 식을 변환하고 결합할 수 있음
- 연산자는 하나 이상의 입력 피연산자(Operand)를 받아 새로운 식을 출력함
예제:
// 상수 식
12
// 연산자를 사용한 식
12 * 30
// 복잡한 식 (괄호로 우선순위 지정)
1 + (12 * 30)
식의 종류
기본 식 (Primary Expressions)
- 언어의 기본적인 구성 요소와 관련된 연산자를 포함한 식임
- 멤버 접근, 메서드 호출 등을 포함함
예제:
// 멤버 접근 연산자(.)와 메서드 호출 연산자(())를 사용
Math.Log(1)
void 식
- 값을 반환하지 않는 식임
- void 식은 다른 식의 피연산자로 사용할 수 없음
예제:
// void 식
Console.WriteLine(1)
// 컴파일 오류 - void 식을 연산에 사용할 수 없음
1 + Console.WriteLine(1)
할당 식 (Assignment Expressions)
- = 연산자를 사용하여 변수에 값을 할당하는 식임
- 할당 식도 값을 가지므로 다른 식의 일부가 될 수 있음
예제:
// 단순 할당
x = 2
// 할당의 결과를 사용
y = 5 * (x = 2) // x에 2를 할당하고 그 값을 사용
// 다중 할당
a = b = c = d = 0 // 모든 변수에 0 할당
- 복합 할당 연산자는 연산과 할당을 결합한 단축 표현임:
x *= 2 // x = x * 2와 동일
x <<= 1 // x = x << 1과 동일
연산자 우선순위와 결합법칙
연산자 우선순위 (Operator Precedence)
- 여러 연산자가 사용된 식에서 계산 순서를 결정함
- 우선순위가 높은 연산자가 먼저 계산됨
예제:
// * 연산자가 + 연산자보다 우선순위가 높음
1 + 2 * 3 // 7 (1 + (2 * 3)와 동일)
연산자의 결합법칙 (Operator Associativity)
왼쪽 결합(Left-associative)
- 대부분의 이항 연산자는 왼쪽에서 오른쪽으로 계산됨
예제:
// 나눗셈 연산자는 왼쪽 결합
8 / 4 / 2 // 1 ((8 / 4) / 2와 동일)
// 괄호로 계산 순서 변경 가능
8 / (4 / 2) // 4
오른쪽 결합(Right-associative)
- 할당 연산자(=), 조건 연산자(?:), 람다 연산자(=>)는 오른쪽에서 왼쪽으로 계산됨
예제:
// 할당 연산자는 오른쪽 결합
x = y = 3 // y에 3을 할당한 후 그 값을 x에 할당
연산자 테이블
분류 연산자 기호 연산자 이름 예제 사용자 재정의 가능
| 기본(Primary) | ||||
| . | 멤버 접근 | x.y | 불가 | |
| ?. | Null 조건 | x?.y | 불가 | |
| () | 함수 호출 | x() | 불가 | |
| [] | 배열/인덱스 | a[x] | 인덱서로 가능 | |
| ++ | 후위 증가 | x++ | 가능 | |
| -- | 후위 감소 | x-- | 가능 | |
| 단항(Unary) | ||||
| + | 양수 값 | +x | 가능 | |
| - | 음수 값 | -x | 가능 | |
| ! | 논리 부정 | !x | 가능 | |
| ~ | 비트 보수 | ~x | 가능 | |
| ++ | 전위 증가 | ++x | 가능 | |
| -- | 전위 감소 | --x | 가능 | |
| 승산(Multiplicative) | ||||
| * | 곱하기 | x * y | 가능 | |
| / | 나누기 | x / y | 가능 | |
| % | 나머지 | x % y | 가능 | |
| 가산(Additive) | ||||
| + | 더하기 | x + y | 가능 | |
| - | 빼기 | x - y | 가능 | |
| 시프트(Shift) | ||||
| << | 왼쪽 시프트 | x << 1 | 가능 | |
| >> | 오른쪽 시프트 | x >> 1 | 가능 | |
| 관계 및 타입(Relational) | ||||
| < | 작음 | x < y | 가능 | |
| > | 큼 | x > y | 가능 | |
| <= | 작거나 같음 | x <= y | 가능 | |
| >= | 크거나 같음 | x >= y | 가능 | |
| is | 타입 검사 | x is y | 불가 | |
| as | 타입 변환 | x as y | 불가 | |
| 동등(Equality) | ||||
| == | 같음 | x == y | 가능 | |
| != | 다름 | x != y | 가능 | |
| 논리(Logical) | ||||
| & | AND | x & y | 가능 | |
| ^ | XOR | x ^ y | 가능 | |
| OR | x | |||
| 조건부(Conditional) | ||||
| && | 조건부 AND | x && y | & 통해 가능 | |
| 조건부 OR | ||||
| ?? | Null 결합 | x ?? y | 불가 | |
| ?: | 조건 | x ? y : z | 불가 | |
| 할당(Assignment) | ||||
| = | 할당 | x = y | 불가 | |
| += | 더하고 할당 | x += y | + 통해 가능 | |
| -= | 빼고 할당 | x -= y | - 통해 가능 | |
| *= | 곱하고 할당 | x *= y | * 통해 가능 | |
| /= | 나누고 할당 | x /= y | / 통해 가능 | |
| %= | 나머지 할당 | x %= y | % 통해 가능 | |
| &= | AND 할당 | x &= y | & 통해 가능 | |
| = | OR 할당 | x | ||
| ^= | XOR 할당 | x ^= y | ^ 통해 가능 | |
| => | 람다 | x => x + 1 | 불가 |
- 위 표는 연산자를 우선순위가 높은 것부터 낮은 순으로 나열한 것임
- 사용자 재정의 가능한 연산자는 연산자 오버로딩을 통해 사용자 정의 타입에 대해 새로운 동작을 정의할 수 있음
예제:
// 연산자 우선순위 예제
int x = 5;
int y = 3;
int z = 2;
// 다양한 연산자 조합
bool result = x + y * z > 10 && x / z == 2 || y % 2 == 1;
// 계산 순서:
// 1. y * z (승산)
// 2. x + (y * z) (가산)
// 3. x / z (승산)
// 4. y % 2 (승산)
// 5. > 10 (관계)
// 6. == 2 (동등)
// 7. == 1 (동등)
// 8. && (조건부 AND)
// 9. || (조건부 OR)
```---
C# 문장(Statement)
문장의 기본 개념
- 문장(Statement)은 프로그램에서 순차적으로 실행되는 코드의 기본 단위임
- 모든 문장은 세미콜론(;)으로 끝나야 함
- 중괄호({})로 여러 문장을 하나의 문장 블록으로 그룹화할 수 있음
선언문(Declaration Statements)
- 변수나 상수를 선언하는 문장임
- 같은 타입의 여러 변수를 쉼표로 구분하여 한 번에 선언할 수 있음
// 변수 선언과 초기화
string someWord = "rosebud";
int someNumber = 42;
bool rich = true, famous = false;
// 상수 선언
const double c = 2.99792458E08;
// c += 10; // 컴파일 오류 - 상수는 변경 불가
지역 변수의 범위(Scope)
- 지역 변수나 상수의 범위는 선언된 블록 내부로 제한됨
- 같은 블록이나 중첩된 블록에서 같은 이름의 변수를 선언할 수 없음
int x;
{
int y;
int x; // 오류 - x가 이미 정의됨
}
{
int y; // 정상 - y가 범위 내에 없음
}
Console.Write(y); // 오류 - y가 범위를 벗어남
식문(Expression Statements)
- 상태를 변경하거나 상태를 변경할 수 있는 것을 호출하는 식으로 구성된 문장임
- 다음과 같은 형태가 가능함:
- 할당식(대입식과 증감식 포함)
- 메서드 호출식(void와 non-void)
- 객체 생성식
// 변수 선언
string s;
int x, y;
System.Text.StringBuilder sb;
// 식문 예제
x = 1 + 2; // 할당식
x++; // 증가식
y = Math.Max(x, 5); // 할당식
Console.WriteLine(y); // 메서드 호출식
sb = new StringBuilder(); // 할당식
new StringBuilder(); // 객체 생성식 (유효하지만 의미 없음)
선택문(Selection Statements)
if 문
- 조건에 따라 코드 블록의 실행 여부를 결정함
- else 절을 사용하여 조건이 거짓일 때 실행할 코드를 지정할 수 있음
if (5 < 2 * 3)
Console.WriteLine("true"); // true 출력
// 코드 블록 사용
if (5 < 2 * 3)
{
Console.WriteLine("true");
Console.WriteLine("Let's move on!");
}
// else 절 사용
if (2 + 2 == 5)
Console.WriteLine("Does not compute");
else
Console.WriteLine("False"); // False 출력
중괄호와 실행 흐름
- else 절은 항상 가장 가까운 if 문에 연결됨
- 중괄호로 실행 흐름을 명시적으로 제어할 수 있음
// 중괄호 없는 경우
if (true)
if (false)
Console.WriteLine();
else
Console.WriteLine("executes"); // 실행됨
// 중괄호로 실행 흐름 변경
if (true)
{
if (false)
Console.WriteLine();
}
else
Console.WriteLine("does not execute"); // 실행되지 않음
switch 문
- 변수의 값에 따라 여러 실행 경로 중 하나를 선택함
- 각 case 절은 명시적인 점프 문장으로 끝나야 함
- break, goto case x, goto default, return, throw, continue 등을 사용할 수 있음
void ShowCard(int cardNumber)
{
switch (cardNumber)
{
case 13:
Console.WriteLine("King");
break;
case 12:
Console.WriteLine("Queen");
break;
case 11:
Console.WriteLine("Jack");
break;
case -1: // 조커는 -1
goto case 12; // Queen으로 처리
default: // 그 외의 경우
Console.WriteLine(cardNumber);
break;
}
}
- 여러 case를 연속으로 나열하여 같은 코드를 실행할 수 있음:
switch (cardNumber)
{
case 13:
case 12:
case 11:
Console.WriteLine("Face card");
break;
default:
Console.WriteLine("Plain card");
break;
}
타입 패턴을 사용한 switch문 (C# 7.0 이상)
- 타입에 따라 다른 동작을 수행할 수 있음
- when 절을 사용하여 추가 조건을 지정할 수 있음
void TellMeTheType(object x)
{
switch (x)
{
case int i:
Console.WriteLine("It's an int!");
Console.WriteLine($"The square of {i} is {i * i}");
break;
case string s:
Console.WriteLine("It's a string");
Console.WriteLine($"The length of {s} is {s.Length}");
break;
case bool b when b == true:
Console.WriteLine("True!");
break;
case bool b:
Console.WriteLine("False!");
break;
default:
Console.WriteLine("I don't know what x is");
break;
}
}
- when b == true → b가 true일때 true
switch 식 (C# 8.0 이상)
- switch를 식으로 사용할 수 있음
- case 절은 화살표(=>)와 식으로 구성됨
string cardName = cardNumber switch
{
//12면 Queen이 반환된다.
13 => "King",
12 => "Queen",
11 => "Jack",
_ => "Pip card" // default와 동일
};
// 튜플 패턴 사용
int cardNumber = 12;
string suite = "spades";
string cardName = (cardNumber, suite) switch
{
(13, "spades") => "King of spades",
(13, "clubs") => "King of clubs",
_ => "Other card"
};
- 튜플 패턴은 공부해놓는게 좋다.
반복문(Iteration Statements)
while과 do-while 문
- while문은 조건이 참인 동안 코드 블록을 반복 실행함
- do-while문은 코드 블록을 먼저 실행한 후 조건을 검사함
// while 문 예제
int i = 0;
while (i < 3)
{
Console.Write(i); // 012 출력
i++;
}
// do-while 문 예제
i = 0;
do
{
Console.WriteLine(i);
i++;
}
while (i < 3);
for 문
- 초기화, 조건, 반복 작업을 한 구문에서 표현함
- 각 절은 생략 가능함
// 기본 for문
for (int i = 0; i < 3; i++)
Console.WriteLine(i);
// 피보나치 수열 계산 예제
for (int i = 0, prevFib = 1, curFib = 1; i < 10; i++)
{
Console.WriteLine(prevFib);
int newFib = prevFib + curFib;
prevFib = curFib;
curFib = newFib;
}
// 무한 루프
for (;;)
Console.WriteLine("interrupt me");
foreach 문
- 열거 가능한 객체의 각 요소에 대해 코드 블록을 실행함
- 배열이나 컬렉션을 순회할 때 유용함
- C++의 범위기반 for문과 비슷한 기능이다.
foreach (char c in "beer")
Console.WriteLine(c);
//string str = "beer"; str[0] -> b
/* 출력:
b
e
e
r
*/
점프문(Jump Statements)
break 문
- 반복문이나 switch문을 즉시 종료함
int x = 0;
while (true)
{
if (x++ > 5)
break; // 루프 종료
}
// break 후 여기서 실행 계속
continue 문
- 현재 반복을 건너뛰고 다음 반복을 시작함
// 짝수 건너뛰기
for (int i = 0; i < 10; i++)
{
if ((i % 2) == 0)
continue;
Console.Write(i + " "); // 1 3 5 7 9 출력
}
return 문
- 메서드를 종료하고 값을 반환함
- void가 아닌 메서드는 반드시 값을 반환해야 함
decimal AsPercentage(decimal d)
{
decimal p = d * 100m;
return p; // 호출자에게 값을 반환
}
throw 문
- 예외를 발생시켜 오류를 알림
if (w == null)
throw new ArgumentNullException();
Null 연산자 (Null Operators)
소개
- C#은 널(null) 값을 더 안전하고 효율적으로 다루기 위한 세 가지 전용 연산자를 제공함
널 병합 연산자 (Null-Coalescing Operator)
- ?? 연산자를 사용함
- 이항 연산자다.
- "왼쪽 피연산자가 널이 아니면 그 값을 사용하고, 널이면 오른쪽 값을 사용함" 이라는 의미다.
- 즉, null이냐 null이 아니냐를 판단하는 연산자다.
// 널 병합 연산자 기본 예제
string s1 = null;
string s2 = s1 ?? "nothing"; // s1이 null이므로 "nothing" 할당됨
Console.WriteLine(s2); // 출력: nothing
string s3 = "something";
string s4 = s3 ?? "nothing"; // s3가 null이 아니므로 "something" 할당됨
Console.WriteLine(s4); // 출력: something
- 오른쪽 식은 왼쪽이 널이 아닐 경우 평가되지 않음
- 널 허용 값 타입(nullable value types)에도 사용 가능함
널 병합 할당 연산자 (Null-Coalescing Assignment Operator)
- C# 8.0부터 도입된 ??= 연산자를 사용함
- "왼쪽 피연산자가 널이면 오른쪽 값을 할당함" 이라는 의미임
// 널 병합 할당 연산자 예제
string str = null;
str ??= "default value"; // str이 null이므로 "default value" 할당됨
Console.WriteLine(str); // 출력: default value
str ??= "new value"; // str이 null이 아니므로 할당되지 않음
Console.WriteLine(str); // 출력: default value
- 다음 코드와 동일한 동작을 함:
if (str == null)
str = "default value";
널 조건 연산자 (Null-Conditional Operator)
- ?. 연산자("엘비스 연산자"라고도 함)를 사용함
- 널 검사와 멤버 접근을 한번에 수행함
- 연산자 왼쪽이 널이면 널을 반환하고, 널이 아니면 오른쪽 멤버를 접근함
- null일수 있지만 호출은 해야하는 상황일때 사용한다.
// 널 조건 연산자 예제
System.Text.StringBuilder sb = null;
string s = sb?.ToString(); // sb가 null이므로 s는 null이 됨
Console.WriteLine(s); // 출력: (아무것도 출력되지 않음)
sb = new System.Text.StringBuilder("test");
s = sb?.ToString(); // sb가 null이 아니므로 ToString() 호출됨
Console.WriteLine(s); // 출력: test
- 인덱서에도 사용 가능함:
string foo = null;
char? c = foo?[1]; // foo가 null이므로 c는 null
- 체인(chain) 형태로 사용 가능함:
System.Text.StringBuilder sb = null;
string s = sb?.ToString()?.ToUpper(); // sb가 null이므로 s는 null
- void 메서드 호출에도 사용 가능함:
StringBuilder sb = null;
sb?.Append("test"); // sb가 null이면 아무 동작도 하지 않음
- 널 조건 연산자와 널 병합 연산자를 함께 사용하면 유용함:
System.Text.StringBuilder sb = null;
string s = sb?.ToString() ?? "nothing"; // 출력: nothing
네임스페이스의 개념
- 네임스페이스(Namespace)는 타입 이름의 범위를 정의하는 영역임
- 타입들을 계층적으로 구성하여 충돌을 방지하고 쉽게 찾을 수 있게 함
- 예를 들어, RSA 암호화를 처리하는 타입은 다음 네임스페이스에 정의되어 있음:
- C++과 다른점 : C++은 네임스페이스::멤버 이렇게 사용했지만, C#은 접근연산자(.)만 사용한다.
System.Security.Cryptography
- 네임스페이스는 타입 이름의 일부로 사용됨:
System.Security.Cryptography.RSA rsa =
System.Security.Cryptography.RSA.Create();
네임스페이스 정의
- namespace 키워드로 타입의 네임스페이스를 정의함:
namespace Outer.Middle.Inner
{
class Class1 {}
class Class2 {}
}
- 점(.)으로 구분된 이름은 중첩된 네임스페이스를 나타냄:
namespace Outer
{
namespace Middle
{
namespace Inner
{
class Class1 {}
class Class2 {}
}
}
}
- 특정 타입을 참조할 때는 전체 네임스페이스 경로를 포함한 정규화된 이름(fully qualified name)을 사용함
- Outer.Middle.Inner.Class1과 같이 표현함
using 지시문
기본 using
- using 지시문으로 네임스페이스를 임포트하면 짧은 이름을 사용할 수 있음:
- 파일 단위로 사용
using Outer.Middle.Inner;
Class1 c; // 전체 경로 없이 사용 가능
전역 using (C# 10)
- global using으로 선언하면 모든 파일에 적용됨:
- 전역적으로 사용
global using System;
global using System.Collections.Generic;
- 프로젝트 파일에서 ImplicitUsings가 true면 다음 네임스페이스들이 자동으로 임포트됨:
- System
- System.Collections.Generic
- System.IO
- System.Linq
- System.Net.Http
- System.Threading
- System.Threading.Tasks
using static
- using static으로 특정 타입의 정적 멤버를 직접 사용할 수 있음:
- 코드를 읽기 힘들어지니 사용하지 않는게 좋다.
using static System.Console;
WriteLine("Hello"); // Console.WriteLine() 대신 사용 가능
네임스페이스 내의 규칙
이름 범위
- 외부 네임스페이스의 이름은 내부 네임스페이스에서 그대로 사용 가능함:
namespace Outer
{
class Class1 {}
namespace Inner
{
class Class2 : Class1 {} // Class1을 바로 사용 가능
}
}
이름 숨김
- 내부 네임스페이스에 같은 이름이 있으면 내부의 이름이 우선함:
namespace Outer
{
class Foo {}
namespace Inner
{
class Foo {} // 이 Foo가 우선함
class Test
{
Foo f1; // Inner.Foo를 가리킴
Outer.Foo f2; // Outer.Foo를 명시적으로 지정
}
}
}
네임스페이스와 타입 별칭
타입 별칭
- 타입 이름 충돌을 피하기 위해 별칭을 사용할 수 있음:
- C++의 typedef와 같은 기능이다.
- 별명을 만드는것과 같다.
using PropertyInfo2 = System.Reflection.PropertyInfo;
class Program { PropertyInfo2 p; }
네임스페이스 별칭
- 전체 네임스페이스에 대한 별칭도 가능함:
using R = System.Reflection;
class Program { R.PropertyInfo p; }
네임스페이스 별칭 한정자
- global 키워드나 별칭으로 모호성을 해결할 수 있음: