// using 지시문: System 네임스페이스의 클래스를 사용하기 위해 필요
using System;
// using static 지시문: Console 클래스 이름을 생략하고 정적 멤버 사용 가능
using static System.Console; //
// namespace 선언: 코드를 논리적으로 묶는 단위 (C# 10부터 파일 범위 가능)
namespace Hello //
{
// class 선언: 실제 프로그램 코드가 작성되는 단위
class MainApp //
{
// 프로그램의 진입점: 프로그램이 시작될 때 가장 먼저 실행
static void Main(string[] args) //
{
// 콘솔에 텍스트 출력
WriteLine("Hello, World!"); //
// 명령행 인수를 사용하는 예 (책 예제 일부)
if (args.Length > 0)
{
WriteLine($"Hello, {args}!"); //
}
}
}
}
파일 범위 네임스페이스
선언이 가능해졌다.static
은 객체 생성 없이도 메서드를 호출할 수 있게 하며, void
는 반환 값이 없음을 의미 string[] args
는 프로그램 실행 시 전달되는 명령행 인수를 받는다.C#은 데이터를 저장하고 다루기 위한 다양한 데이터 형식을 제공
byte
, short
, int
, long
등 부호 있는 정수 형식과 uint
등 부호 없는 정수 형식_
)나 2진수(0b
), 16진수(0x
)로 표현int a = 1_000_000; // 자릿수 구분자
byte b = 0b1111_0000; // 2진수 리터럴
uint c = 0xF0_0000; // 16진수 리터럴
float
, double
등이 있습니다. float
리터럴에는 f
또는 F
를 붙임float f = 3.14f; // float 리터럴
double d = 3.1415926535; // double 리터럴
m
또는 M
을 붙임decimal money = 1000.50m; // decimal 리터럴
bool
이 있으며, 참/거짓 (true
/false
) 값을 가지고, 1바이트 크기를 가짐bool isTrue = true; //
bool isFalse = false; //
char
가 있으며, 작은따옴표('
)로 하나의 문자를 표현char initial = 'A'; //
string
이 있으며, 큰따옴표("
)로 문자의 나열을 표현, 여러 줄에 걸친 문자열은 @""
또는 """..."""
(C# 8 이상) 구문을 사용할 수 있다.string name = "홍길동"; //
string multiline = """
첫 번째 줄
두 번째 줄
세 번째 줄
"""; //
object anyData = 123; // int 값을 담음
anyData = "Hello"; // string 값을 담음
형 변환 (Type Conversion): 데이터를 다른 형식으로 바꾸는 것을 말한다. 작은 형식에서 큰 형식으로 변환 시에는 데이터 손실 위험이 없어 암시적 형 변환
이 일어나지만, 큰 형식에서 작은 형식으로 변환 시에는 명시적 형 변환 (Casting)
이 필요하며 오버플로가 발생할 수 있다.
int a = 123;
long b = a; // 암시적 형 변환
byte x = 100;
int y = x; // 암시적 형 변환
int i = 255;
// byte j = i; // 오류 발생 (암시적 변환 불가)
byte j = (byte)i; // 명시적 형 변환 (byte j = 255)
sbyte sb = (sbyte)a; // sbyte의 최대값 127보다 크므로 오버플로 발생
```
문자열과 숫자 형식을 상호 변환할 때는 `Parse`, `TryParse`, `Convert` 메서드를 사용, 특히 `TryParse`는 변환 성공 여부를 bool 값으로 반환하여 예외 발생 없이 안전하게 변환을 시도할 수 있다.
string strNum = "12345";
int num1 = int.Parse(strNum); //
string strFloat = "3.14f";
float floatVal;
if (float.TryParse(strFloat, out floatVal)) // TryParse 사용 예
{
WriteLine($"변환 성공: {floatVal}");
}
int num2 = Convert.ToInt32("999"); //
string strFromNum = num2.ToString(); // 숫자를 문자열로
```
박싱 (Boxing)과 언박싱 (Unboxing): 값 형식(int, float 등)의 데이터를 object 형식으로 변환하는 것을 박싱, object 형식 데이터를 다시 값 형식으로 변환하는 것을 언박싱이라고 한다.
int num = 10;
object obj = num; // 박싱
int num2 = (int)obj; // 언박싱
```
박싱(boxing) = 값타입에서 참조타입으로 변환하는 과정
언박싱(un-boxing) = 참조타입에서 값타입으로 변환하는 과정
상수 (const): 값을 한 번 할당하면 변경할 수 없는 변수, 선언과 동시에 초기화해야 한다.
const int MAX_VALUE = 100; //
const string GREETING = "Hello"; //
// MAX_VALUE = 200; // 컴파일 오류 발생
열거 형식 (enum): 연관된 정수형 상수들의 집합에 이름을 붙여 관리할 때 사용, 가독성과 유지보수성을 높임
enum DialogResult { YES, NO, CANCEL, CONFIRM, OK } //
DialogResult result = DialogResult.YES; //
WriteLine((int)DialogResult.OK); // 기본값은 0부터 시작하며 정수형으로 변환 가능
enum ErrorCode : short { None = 0, Unknown = 1, Timeout = 50 } // 기반 형식을 short로 지정 및 값 할당
Nullable 형식 (?
): 값 형식 변수는 기본적으로 null
값을 가질 수 없다. Nullable 형식을 사용하면 값 형식 변수도 null
을 가질 수 있게 된다.
데이터 형식 뒤에 ?
를 붙여 선언한다. HasValue
속성으로 null
여부를, Value
속성으로 실제 값을 확인한다.
* ```csharp
int? nullableInt = null; // null 허용
// int nonNullableInt = null; // 오류
if (nullableInt.HasValue) // null인지 확인
{
int value = nullableInt.Value; // 값 가져오기
WriteLine($"Value is: {value}");
} else {
WriteLine("nullableInt is null"); //
}
nullableInt = 100; // 값 할당 가능
```
var 키워드: 지역 변수를 선언할 때 사용하며, 컴파일러가 초기화 식을 보고 자동으로 데이터 형식을 유추하게 한다. 코드를 간결하게 만들 수 있지만, 가독성을 위해 적절히 사용해야 한다. 반드시 선언과 동시에 초기화해야 한다. 클래스의 필드에는 사용할 수 없다.
var age = 30; // 컴파일러가 int로 유추
var message = "Hello!"; // 컴파일러가 string으로 유추
var numbers = new int[] { 1, 2, 3 }; // 컴파일러가 int[]로 유추
// var noValue; // 오류: 초기화 필요
C#은 다양한 연산자를 제공하여 데이터를 조작한다.
산술 연산자: +, -, *, /, % (나머지).
int sum = 10 + 5; // 덧셈
double division = 7.0 / 2.0; // 나눗셈
int remainder = 7 % 2; // 나머지
증감 연산자: ++
(1 증가), --
(1 감소). 변수 앞/뒤에 따라 연산 시점이 달라진다.
int i = 0;
i++; // i는 1이 됨
++i; // i는 2가 됨
int a = 10;
int b = a++; // b는 10, a는 11
int c = --a; // c는 10, a는 10
문자열 결합 연산자: +
연산자를 사용하여 문자열을 연결할 수 있다.
string greeting = "Hello" + " " + "World!"; //
관계 연산자: >, <, >=, <=, == (같다), != (다르다). 두 값의 관계를 비교하여 bool
값을 반환한다.
bool isEqual = (5 == 5); // true
bool isGreater = (10 > 20); // false
논리 연산자: &&
(AND), ||
(OR), !
(NOT). bool
값을 가지고 논리 연산을 수행한다.
bool condition1 = true;
bool condition2 = false;
bool resultAnd = condition1 && condition2; // false
bool resultOr = condition1 || condition2; // true
bool resultNot = !condition1; // false
조건 연산자 (삼항 연산자): 조건식 ? 참일_때_값 : 거짓일_때_값
형태. 조건에 따라 두 값 중 하나를 선택한다.
int age = 20;
string status = (age >= 19) ? "성인" : "미성년자"; //
WriteLine($"나이는 {age}세, 상태는 {status}"); //
Null 조건 연산자 (?.
, ?[]
): 객체가 null
이 아닐 때만 멤버 접근이나 요소 접근을 수행한다. null
이면 뒤의 연산을 수행하지 않고 null
을 반환한다.
int[] numbers = null;
// int count = numbers.Length; // numbers가 null이면 예외 발생
int? count = numbers?.Length; // numbers가 null이면 count는 null이 됨
WriteLine($"Count: {count}"); // null 출력
numbers = new int[] { 1, 2, 3 };
count = numbers?.Length; // numbers가 null이 아니므로 count는 3이 됨
WriteLine($"Count: {count}"); // 3 출력
Null 병합 연산자 (??
): 왼쪽 피연산자가 null
이면 오른쪽 피연산자 값을 반환하고, null
이 아니면 왼쪽 피연산자 값을 반환한다.
string str = null;
string result = str ?? "기본값"; // str이 null이므로 "기본값"이 result에 할당됨
WriteLine(result); // 기본값 출력
str = "실제값";
result = str ?? "기본값"; // str이 null이 아니므로 "실제값"이 result에 할당됨
WriteLine(result); // 실제값 출력
할당 연산자: =
(대입), +=
, -=
, *=
, /=
, %=
등. 연산 후 대입을 동시에 수행한다.
int x = 10; // 대입
x += 5; // x = x + 5; (x는 15)
x *= 2; // x = x * 2; (x는 30)
비트 연산자: &
, |
, ^
, ~
, <<
, >>
등. 데이터를 비트 단위로 조작한다.
int a = 5; // 0101
int b = 3; // 0011
int resultAnd = a & b; // 0001 (1)
int resultOr = a | b; // 0111 (7)
int resultXor = a ^ b; // 0110 (6)
int shifted = a << 1; // 1010 (10)
프로그램의 실행 흐름을 제어하는 구문입니다.
조건문:
int number = 10;
if (number > 0) // 조건식
{
WriteLine("양수입니다."); // 조건이 참일 때 실행
} else if (number < 0) //
{
WriteLine("음수입니다."); //
} else
{
WriteLine("0입니다."); //
}
case
와 비교하여 해당 블록을 실행합니다. 각 case
끝에는 보통 break
를 사용하여 switch
문을 빠져나온다.string day = "월";
switch (day) //
{
case "월": //
WriteLine("월요일입니다."); //
break; //
case "화": //
WriteLine("화요일입니다."); //
break; //
default: //
WriteLine("알 수 없는 요일입니다."); //
break; //
}
switch
문입니다.int score = 85;
string grade = score switch //
{
>= 90 => "A", //
>= 80 => "B", //
>= 70 => "C", //
>= 60 => "D", //
_ => "F" // 그 외의 경우
};
WriteLine($"점수: {score}, 학점: {grade}"); //
반복문: 코드 블록을 여러 번 실행할 때 사용
int count = 5;
while (count > 0) // 조건식
{
WriteLine($"Count: {count}"); //
count--; //
}
// 출력: 5, 4, 3, 2, 1
int i = 0;
do //
{
WriteLine($"i: {i}"); //
i++; //
} while (i < 3); // 조건식
// 출력: 0, 1, 2
for (int j = 0; j < 5; j++) // 초기화; 조건식; 반복식
{
WriteLine($"j: {j}"); //
}
// 출력: 0, 1, 2, 3, 4
무한 반복은 for (;;)
또는 while (true)
와 같이 작성한다.string[] fruits = { "Apple", "Banana", "Cherry" };
foreach (string fruit in fruits) //
{
WriteLine(fruit); //
}
// 출력: Apple, Banana, Cherry