기본 문법
기본 자료형
정수형
| 자료형 | 크기 | 기본값 | 범위 | .NET Framework 형식 |
| -------- | -------- | -------- | -------- | -------- | -------- |
| sbyte
| 1byte | 0 | 0255 | System.SByte |
| 127 | System.Byte |
| byte
| 1byte | 0 | -128short
| 2byte | 0 | -32,76832,767 | System.Int16 |
| 65,535 | System.UInt16 |
| ushort
| 2byte | 0 | 0int
| 4byte | 0 | -2,147,483,6482,147,483,647 | System.Int32 |
| 4,294,967,295 | System.Int32 |
| uint
| 4byte | 0 | 0long
| 8byte | 0L | -9,223,372,036,854,775,8089,223,372,036,854,775,807 | System.Int64 |
| 18,446,744,073,709,551,615 | System.UInt64 |ulong
| 8byte | 0 | 0
실수형
| 자료형 | 크기 | 기본값 | 범위 | .NET Framework 형식 |
| -------- | -------- | -------- | -------- | -------- | -------- |
| float
| 4byte | 0.0F | 0255 | System.Single |
| 127 | System.Double |
| double
| 8byte | 0.0D | -128decimal
| 162byte | 0.0M | -32,768~32,767 | System.Decimal |
문자형
| 자료형 | 크기 | 기본값 | 범위 | .NET Framework 형식 |
| -------- | -------- | -------- | -------- | -------- | -------- |
| char
| 2byte | ‘\0’ | U+0000~U+FFFF | System.Char |
| string
| | | 문자열 | System.String |
논리형
| 자료형 | 크기 | 기본값 | 범위 | .NET Framework 형식 |
| -------- | -------- | -------- | -------- | -------- | -------- |
| bool
| | false | true, false | System.Boolean |
var 형식
변수의 형식을 반드시 지정해줄 필요 없이 var 형식을 사용하여 값의 종류에 따라 컴파일러가 유추하여 사용한다.
var i = 3; // int
var d = 3.0; // double
var s = "value"; // String
Console.WriteLine(i.GetType().FullName()); // 출력 결과 : System.Int32
Console.WriteLine(i.GetType().FullName()); // 출력 결과 : System.Double
Console.WriteLine(i.GetType().FullName()); // 출력 결과 : System.String
Nullable 형식
Nullable 형식은 내부 형식의 값 이외에도 null
값을 저장할 수 있는 형식이다. *Nullable*과 같이 구조체로 표기하지만, 값 형식에 ‘?’를 붙여 사용할 수 있다. 예를 들어 Nullable<bool>
또는 bool?
형식은 내부 값인 true
, false
또는 null
값을 저장할 수 있다. HasValue
속성을 사용하면 값이 저장됐는지를 Boolean 값으로 반환하고, 값이 있다면 Value
속성을 사용하면 실제 저장된 값을 반환한다.
int? intValue1 = null;
int? intValue2 = 2;
intValue2++; // 값이 저장되어 있으므로 연산할 수 있다.
if ( intValue1 == null ) // true
if ( intValue2 == null ) // false
Console.WriteLine(intValue1.HasValue); // 출력 결과 : false
Console.WriteLine(intValue2.HasValue); // 출력 결과 : true
Console.WriteLine(intValue2.Value); // 출력 결과 : 3
Console.WriteLine(intValue2); // 출력 결과 : 3
구조체
구조체는 다양한 형식의 변수와 Method를 묶어 사용자가 원하는 형식으로 정의한 것이다. Value Type이기 때문에 구조체를 선언하면 Stack 공간에 할당된다. 구조체 내의 변수는 매개 변수가 있는 생성자를 호출하거나, ‘.’ 연산자를 이용해 접근하여 값을 초기화한다.
public struct Position
{
public int x,;
public int y;
public Position(int p1, int p2)
{
x = p1;
y = p2;
}
}
구조체의 특징
- 구조체의 필드는
const
또는static
으로 선언한 경우에만 초기화를 할 수 있다. - 매개 변수가 없는 생성자인 기본 생성자를 명시적으로 선언할 수 없다.
- 매개 변수가 있는 생성자는 선언할 수 있다. 단, 모든 필드에 값을 초기화해야 한다.
- 클래스와 달리 매개 변수가 있는 생성자를 선언하면, 기본 생성자는 묵시적으로 선언 된다.
- 인터페이스를 구현할 수는 있지만, 다른 구조체를 상속할 수는 없다.
-
new
연산자를 사용하여 선언해도 되고, 사용하지 않고 선언해도 된다. -
Nullable 형식을 사용하여
null
값을 할당할 수 있다.
Stack vs. Heap
Stack
Stack은 가장 나중에 들어간 데이터가 먼저 출력(LIFO, Last In First Out)된다는 특징을 가진 자료구조이다. Stack은 자료구조에서 다루는 Stack의 원리로 데이터를 저장하는 메모리 공간이다. Thread는 이 공간을 활용해서 Method의 실행, 지역변수 선언, 호출 후 실행될 주소를 처리한다. Stack은 기본적으로 1MB 공간을 할당하는데 이 공간을 넘어가면 Stack Overflow가 발생한다. 예를 들어 재귀(recursive)로 Method를 계속해서 호출하면 Stack의 공간이 모두 사용되어 Stack Overflow가 발생한다. 이 경우 오류를 알리는 Method를 호출할 공간조차 없기 때문에 정확한 원인을 파악하는 데 어려움이 있다.
Heap
Heap은 프로그램 실행 중 필요로 요청했을 때 저장하는 메모리 공간이다. 어느 시점에 어느 정도의 메모리 공간이 필요한지를 예상할 수 없으므로 Heap의 크기는 프로그램 실행 중에 결정된다. C#에서는 new
연산자로 참조 형식의 변수 또는 객체를 선언하면 Heap에 할당된다. 또한, **CLR(Common Language Runtime)**의 Garbage Collector가 실행되면서 Heap을 관리하기 때문에 사용되지 않는 공간은 해제하여 여유 공간을 확보한다.
Value Type vs. Reference Type
Value Type
Value Type은 변수의 값 자체가 Stack에 할당되는 형식이다. 기본 자료형(string은 예외) 또는 구조체 중 배열이 아닌 하나로 선언한 변수가 Value Type에 속하다,
Reference Type
Reference Type은 데이터를 저장하기 위해 Heap에 메모리를 할당하고, Stack의 변수에는 Heap에 할당된 데이터의 주소를 가리키는 형식이다. 기본 자료형의 string, 배열, 클래스, 클래스 등이 Reference Type에 속한다.
Value type과 Reference type 비교
구분 | Value type | Reference type |
---|---|---|
할당 위치 | Stack | Heap |
저장 내용 | 데이터(값) | 데이터가 위치한 메모리 주소 |
변수 종류 | 기본 자료형(string 제외), 구조체, 열거형 | string, 배열, 클래스 등 |
매개 변수 | Call by Value | Call by Reference |
소멸 시기 | 정의한 범위를 벗어날 때 | Garbage Collector에 의해 |
제어문 (선택문)
if 문
if 문은 괄호 안에 조건식을 지정한 후에 그 결과가 true
이면 포함된 구문을 실행하고, false
이면 실행하지 않고 다음 코드로 넘어간다. 결과가 false
인 경우에도 else
를 사용해 구문을 추가할 수 있고, else if
를 사용해 조건을 중첩할 수도 있다.
int number = 3;
if ( number > 0 )
{
Console.WriteLine("Positive Number");
}
else if ( number < 0 )
{
Console.WriteLine("Negative Number");
}
else
{
Console.WriteLine("Zero");
}
// 출력 결과 : Positive Number
조건 연산자
조건 연산자(또는 삼항 연산자)는 조건식의 결과인 treu
또는 false
에 따라 표현식의 두 값 중 하나를 반환한다. 조건식의 결과가 true
이면 표현식1을 반환하고, false
이면 표현식2를 반환한다.
(조건식) ? 표현식1 : 표현식2;
int number = 3;
string result;
result = (number % 2 == 0) ? "짝수" : "홀수";
Console.WriteLine(result); // 출력 결과 : 홀수
switch 문
switch 문은 조건식과 같은 경우를 선택하여 해당 구문을 실행한다. case
안에 구문 마지막에는 break
을 사용해야 swtich 문을 끝낼 수 있으며, default
사용하여 나머지 조건에 해당하는 구문을 실행할 수도 있다.
int value = 1;
switch (value)
{
case 1:
Console.WriteLine("Case 1");
break;
case 2:
Console.WriteLine("Case 2");
break;
default:
Console.WriteLine("Default case");
break; // 생략 가능
}
// 실행 결과 : Case 1
제어문 (반복문)
for 문
for 문은 초기화 코드가 실행 후 조건식 -> 구문 -> 반복문을 번갈아 가며 조건식의 결과가 false
가 될 때까지 실행을 반복한다.
for ( 초기화; 조건식; 반복문 )
구문;
int sum = 0;
for (int i = 1; i <= 5; i++)
{
sum += i;
}
Console.WriteLine(sum); // 실행 결과 : 15
foreach 문
foreach 문은 배열이나 Collection에 있는 데이터를 처음부터 끝까지 반복하면서 선언된 변수에 각 요소를 넣어 구문 안에서 해당 변수를 사용할 수 있게 해준다.
foreach ( 자료형 변수명 in 표현식 )
구문;
int [] array = new int[] { 1, 2, 3, 4, 5 };
int sum = 0;
foreach (int element in array )
{
sum+= element;
}
Console.WriteLine(sum); // 실행 결과 : 15
while 문
while 문은 조건식의 결과가 false
가 될 때까지 반복할 구문을 실행하면서 반복한다.
while (조건식)
구문;
int i;
int sum = 0;
i = 1;
while (i <= 5)
{
sum += i;
i++;
}
Console.WriteLine(sum); // 실행 결과 : 15
do-while 문
do-while 문은 while 문과 마찬가지로 조건식의 결과가 false
일 때까지 포함된 구문을 실행하면서 반복한다. while 문은 처음 실행될 때 조건식을 먼저 확인하지만, do-while 문은 조건식의 결과와 상관없이 반복할 구문을 최소 한번은 실행한다.
do
구문;
while (조건식);
int i;
int sum = 0;
i = 1;
do
{
sum += i;
i++;
} while (i <= 5);
Console.WriteLine(sum); // 실행 결과 : 15
제어문 (점프문)
break 문
break 문은 switch
또는 for
/foreach
/while
/do
와 같은 반복문 내에서만 사용될 수 있다. switch 문 또는 break
를 둘러싸고 있는 반복문을 종료하는 데 사용한다.
int sum = 0;
for (int i = 1; i <= 100; i++)
{
sum += i;
if (i == 5)
{
break;
}
}
Console.WriteLine(sum); // 실행 결과 : 15
continue 문
continue 문은 반복문 내에서 continue 문 이후의 구문을 생략하고 다음 조건식을 실행하는 데 사용한다.
int sum = 0;
for (int i = 1; i <= 10; i++)
{
if (i % 2 == 0)
{
continue;
}
sum += i;
}
Console.WriteLine(sum); // 실행 결과 : 25
goto 문
goto 문은 미리 선언된 레이블 문으로 제어의 흐름을 옮기는 데 사용한다.
return 문
return 문은 자신이 속한 Method의 실행을 종료하고 호출한 Method로 반환시킨다. 이때 반환할 값이 있으면 같이 반환된다. void
형식의 Method의 경우는 return 문을 생략할 수 있다.
int computeArea(int width, int height)
{
int area = width * height;
return area;
}
연산자
종류 | 연산자 |
---|---|
관계 연산자 | >, <, >=, <=, ==, != |
논리 연산자 | &&, |
산술 연산자 | +, -, *, /, % |
대입 연산자 | =, +=, -=, *=, /=, &= |
대입 연산자 | ++, -- |
연산자 | 특징 | 예시 |
---|---|---|
new |
배열 선언 또는 객체를 선언하고 생성자를 호출 | Object obj = new Object(); |
typeof(T) |
T에 대한 형식 객체를 반환 | Type t = typeof(int); |
checked |
산술 연산 및 변환에 대한 Overflow를 검사 | checked(2147483647 + ten) |
unchecked |
산술 연산 및 변환에 대한 Overflow 검사를 무시 | unchecked(2147483647 + ten) |
default(T) |
T 형식의 기본값을 반환 | T temp = default(int); |
delegate |
Anonymous Method를 정의 | Del d = delegate() { } |
await |
기다리던 작업이 완료될 때까지 비동기 Method를 일시 중단 | byte[] urlContents = await getContentsTask; |
is |
형 변환에 대한 가능성 여부를 true , false 로 반환 |
if (d as Base) |
as |
형 변환이 가능하면 변환된 값을 반환하고, 불가능하면 null 을 반환 |
Base b = d as Base; |
?? |
피연산자가 null 이 아닐 경우 왼쪽 피연산자를 반환하고, null 일 경우 오른쪽 피연산자를 반환 |
x ?? -1 |
=> |
Lambda 식을 사용 | (a, b) => a + b |