C#은 Microsoft에서 개발한 객체지향 프로그래밍 언어로, .NET 플랫폼의 핵심 언어이다. 이 글은 C# 문법을 기초부터 고급 기능까지 체계적으로 정리한다. 각 개념은 실제 코드 예제와 함께 설명하여 실무에서 바로 활용할 수 있도록 구성하였다.

1. 기본 문법 (Basic Syntax)

1.1 변수와 타입 (Variables and Types)

C#은 정적 타입 언어로, 모든 변수는 명시적으로 타입을 선언해야 한다.

기본 타입 (Primitive Types)

// 정수 타입
byte b = 255;              // 0 ~ 255 (8-bit)
sbyte sb = -128;            // -128 ~ 127 (8-bit signed)
short s = -32768;           // -32,768 ~ 32,767 (16-bit)
ushort us = 65535;          // 0 ~ 65,535 (16-bit unsigned)
int i = -2147483648;        // -2,147,483,648 ~ 2,147,483,647 (32-bit)
uint ui = 4294967295;       // 0 ~ 4,294,967,295 (32-bit unsigned)
long l = -9223372036854775808L;  // 64-bit
ulong ul = 18446744073709551615UL; // 64-bit unsigned

// 부동소수점 타입
float f = 3.14f;            // 32-bit (접미사 f 필수)
double d = 3.141592653589793; // 64-bit
decimal dec = 3.14159265358979323846m; // 128-bit (접미사 m 필수, 금융 계산용)

// 문자 타입
char c = 'A';               // 16-bit Unicode
string str = "Hello, World!"; // 참조 타입

// 불리언 타입
bool flag = true;           // true 또는 false

// 객체 타입
object obj = new object();  // 모든 타입의 기본 클래스

타입 추론 (Type Inference)

C# 3.0부터 var 키워드를 사용하여 타입 추론이 가능하다.

var number = 42;            // int로 추론
var name = "C#";            // string으로 추론
var list = new List<int>(); // List<int>로 추론

// var는 지역 변수에만 사용 가능
// var는 초기화와 함께 선언되어야 함
// var x; // 컴파일 오류

상수 (Constants)

const int MaxValue = 100;
const string AppName = "MyApp";
const double Pi = 3.14159;

// readonly 필드 (런타임 상수)
readonly int ReadOnlyValue;
public MyClass(int value)
{
    ReadOnlyValue = value; // 생성자에서만 할당 가능
}

1.2 연산자 (Operators)

산술 연산자

int a = 10, b = 3;
int sum = a + b;        // 13
int diff = a - b;       // 7
int prod = a * b;       // 30
int quot = a / b;       // 3 (정수 나눗셈)
int rem = a % b;        // 1 (나머지)

// 증감 연산자
int x = 5;
x++;                    // x = 6 (후위)
++x;                    // x = 7 (전위)
x--;                    // x = 6 (후위)
--x;                    // x = 5 (전위)

비교 연산자

int a = 10, b = 20;
bool eq = a == b;       // false (같음)
bool ne = a != b;       // true (다름)
bool gt = a > b;        // false (큼)
bool lt = a < b;        // true (작음)
bool ge = a >= b;       // false (크거나 같음)
bool le = a <= b;       // true (작거나 같음)

논리 연산자

bool p = true, q = false;
bool and = p && q;      // false (논리 AND)
bool or = p || q;       // true (논리 OR)
bool not = !p;          // false (논리 NOT)

// 비트 연산자
int x = 5, y = 3;       // 5 = 101, 3 = 011
int bitAnd = x & y;     // 1 (001)
int bitOr = x | y;      // 7 (111)
int bitXor = x ^ y;     // 6 (110)
int bitNot = ~x;        // -6 (비트 반전)
int leftShift = x << 1; // 10 (왼쪽 시프트)
int rightShift = x >> 1; // 2 (오른쪽 시프트)

null 관련 연산자

// null 조건부 연산자 (?.)
string str = null;
int? length = str?.Length; // null (NullReferenceException 방지)

// null 병합 연산자 (??)
string name = null;
string displayName = name ?? "Unknown"; // "Unknown"

// null 병합 할당 연산자 (??=)
string value = null;
value ??= "Default";    // value가 null이면 "Default" 할당

1.3 문자열 (Strings)

// 문자열 연결
string firstName = "John";
string lastName = "Doe";
string fullName = firstName + " " + lastName; // "John Doe"

// 문자열 보간 (String Interpolation)
string message = $"Hello, {firstName} {lastName}!"; // C# 6.0+

// 문자열 포맷
string formatted = string.Format("Value: {0}, Name: {1}", 42, "Test");

// 문자열 메서드
string text = "Hello, World!";
int length = text.Length;                    // 13
string upper = text.ToUpper();              // "HELLO, WORLD!"
string lower = text.ToLower();              // "hello, world!"
bool contains = text.Contains("World");      // true
string substring = text.Substring(0, 5);   // "Hello"
string[] parts = text.Split(',');           // ["Hello", " World!"]
string trimmed = "  text  ".Trim();         // "text"
bool starts = text.StartsWith("Hello");     // true
bool ends = text.EndsWith("!");             // true
int index = text.IndexOf("World");         // 7
string replaced = text.Replace("World", "C#"); // "Hello, C#!"

2. 제어문 (Control Flow)

2.1 조건문 (Conditional Statements)

if-else

int score = 85;

if (score >= 90)
{
    Console.WriteLine("A");
}
else if (score >= 80)
{
    Console.WriteLine("B");
}
else if (score >= 70)
{
    Console.WriteLine("C");
}
else
{
    Console.WriteLine("F");
}

// 삼항 연산자
string grade = score >= 60 ? "Pass" : "Fail";

switch

int day = 3;
string dayName;

switch (day)
{
    case 1:
        dayName = "Monday";
        break;
    case 2:
        dayName = "Tuesday";
        break;
    case 3:
        dayName = "Wednesday";
        break;
    default:
        dayName = "Unknown";
        break;
}

// switch 표현식 (C# 8.0+)
string dayName2 = day switch
{
    1 => "Monday",
    2 => "Tuesday",
    3 => "Wednesday",
    _ => "Unknown"
};

// 패턴 매칭 (C# 7.0+)
object obj = 42;
switch (obj)
{
    case int i when i > 0:
        Console.WriteLine($"Positive integer: {i}");
        break;
    case string s:
        Console.WriteLine($"String: {s}");
        break;
    case null:
        Console.WriteLine("Null");
        break;
    default:
        Console.WriteLine("Unknown");
        break;
}

2.2 반복문 (Loops)

for

// 기본 for 루프
for (int i = 0; i < 10; i++)
{
    Console.WriteLine(i);
}

// 중첩 for 루프
for (int i = 0; i < 3; i++)
{
    for (int j = 0; j < 3; j++)
    {
        Console.WriteLine($"({i}, {j})");
    }
}

while

int count = 0;
while (count < 5)
{
    Console.WriteLine(count);
    count++;
}

// do-while
int num = 0;
do
{
    Console.WriteLine(num);
    num++;
} while (num < 5);

foreach

int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int num in numbers)
{
    Console.WriteLine(num);
}

// 컬렉션 순회
List<string> names = new List<string> { "Alice", "Bob", "Charlie" };
foreach (string name in names)
{
    Console.WriteLine(name);
}

// 인덱스와 함께 순회
for (int i = 0; i < names.Count; i++)
{
    Console.WriteLine($"{i}: {names[i]}");
}

반복문 제어

// break: 루프 종료
for (int i = 0; i < 10; i++)
{
    if (i == 5)
        break;  // 루프 종료
    Console.WriteLine(i);
}

// continue: 다음 반복으로 건너뛰기
for (int i = 0; i < 10; i++)
{
    if (i % 2 == 0)
        continue;  // 짝수는 건너뛰기
    Console.WriteLine(i);
}

// goto (권장하지 않음)
for (int i = 0; i < 10; i++)
{
    if (i == 5)
        goto EndLoop;
    Console.WriteLine(i);
}
EndLoop:
Console.WriteLine("Loop ended");

3. 배열과 컬렉션 (Arrays and Collections)

3.1 배열 (Arrays)

// 배열 선언 및 초기화
int[] numbers = new int[5];              // 크기 5, 기본값 0
int[] numbers2 = new int[] { 1, 2, 3, 4, 5 };
int[] numbers3 = { 1, 2, 3, 4, 5 };     // 간단한 문법

// 다차원 배열
int[,] matrix = new int[3, 3];          // 2차원 배열
int[,,] cube = new int[2, 2, 2];        // 3차원 배열

// 가변 배열 (Jagged Array)
int[][] jagged = new int[3][];
jagged[0] = new int[] { 1, 2, 3 };
jagged[1] = new int[] { 4, 5 };
jagged[2] = new int[] { 6, 7, 8, 9 };

// 배열 메서드
int[] arr = { 3, 1, 4, 1, 5 };
Array.Sort(arr);                         // 정렬
Array.Reverse(arr);                      // 역순
int index = Array.IndexOf(arr, 4);      // 인덱스 찾기
int length = arr.Length;                 // 길이

3.2 리스트 (List)

// List 선언 및 초기화
List<int> numbers = new List<int>();
List<string> names = new List<string> { "Alice", "Bob" };

// 요소 추가/제거
numbers.Add(1);
numbers.AddRange(new int[] { 2, 3, 4 });
numbers.Insert(0, 0);                    // 인덱스 0에 삽입
numbers.Remove(3);                       // 값 3 제거
numbers.RemoveAt(0);                     // 인덱스 0 제거
numbers.Clear();                         // 모두 제거

// 요소 접근
int first = numbers[0];                 // 인덱스로 접근
bool contains = numbers.Contains(2);    // 포함 여부
int count = numbers.Count;              // 개수
int index = numbers.IndexOf(2);         // 인덱스 찾기

// 정렬 및 검색
numbers.Sort();                          // 정렬
numbers.Reverse();                       // 역순
bool exists = numbers.Exists(x => x > 5); // 조건 검색
List<int> filtered = numbers.FindAll(x => x > 2); // 필터링

3.3 딕셔너리 (Dictionary)

// Dictionary 선언 및 초기화
Dictionary<string, int> ages = new Dictionary<string, int>();
Dictionary<string, string> capitals = new Dictionary<string, string>
{
    { "Korea", "Seoul" },
    { "Japan", "Tokyo" },
    { "USA", "Washington" }
};

// 요소 추가/제거
ages["Alice"] = 25;
ages.Add("Bob", 30);
ages.Remove("Alice");
bool removed = ages.Remove("Bob");

// 요소 접근
int age = ages["Alice"];                 // 키로 접근
bool hasKey = ages.ContainsKey("Bob");   // 키 존재 여부
bool hasValue = ages.ContainsValue(25);  // 값 존재 여부

// 순회
foreach (var kvp in ages)
{
    Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}

foreach (string key in ages.Keys)
{
    Console.WriteLine(key);
}

foreach (int value in ages.Values)
{
    Console.WriteLine(value);
}

3.4 기타 컬렉션

// HashSet (중복 없는 집합)
HashSet<int> set = new HashSet<int> { 1, 2, 3, 3 }; // {1, 2, 3}
set.Add(4);
bool added = set.Add(2);                 // false (이미 존재)

// Queue (FIFO)
Queue<string> queue = new Queue<string>();
queue.Enqueue("First");
queue.Enqueue("Second");
string first = queue.Dequeue();          // "First"
string peek = queue.Peek();              // "Second" (제거하지 않음)

// Stack (LIFO)
Stack<int> stack = new Stack<int>();
stack.Push(1);
stack.Push(2);
int top = stack.Pop();                   // 2
int peek2 = stack.Peek();                // 1 (제거하지 않음)

4. 클래스와 객체 (Classes and Objects)

4.1 클래스 정의

// 기본 클래스
public class Person
{
    // 필드 (Fields)
    private string name;
    private int age;

    // 속성 (Properties)
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public int Age
    {
        get => age;
        set => age = value;
    }

    // 자동 속성 (Auto-Property)
    public string Email { get; set; }

    // 읽기 전용 속성
    public string FullName { get; private set; }

    // 생성자 (Constructor)
    public Person()
    {
        name = "Unknown";
        age = 0;
    }

    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    // 메서드 (Methods)
    public void Introduce()
    {
        Console.WriteLine($"I'm {name}, {age} years old.");
    }

    public string GetInfo()
    {
        return $"{name} ({age})";
    }
}

// 사용 예제
Person person = new Person("Alice", 25);
person.Introduce();

4.2 접근 제한자 (Access Modifiers)

public class Example
{
    public int PublicField;           // 어디서나 접근 가능
    private int PrivateField;         // 같은 클래스 내에서만
    protected int ProtectedField;     // 같은 클래스 및 파생 클래스
    internal int InternalField;       // 같은 어셈블리 내에서만
    protected internal int ProtectedInternalField; // protected 또는 internal
    private protected int PrivateProtectedField;   // private 또는 protected (C# 7.2+)
}

4.3 정적 멤버 (Static Members)

public class MathHelper
{
    // 정적 필드
    public static int Count = 0;

    // 정적 메서드
    public static int Add(int a, int b)
    {
        return a + b;
    }

    // 정적 속성
    public static double Pi { get; } = 3.14159;

    // 정적 생성자
    static MathHelper()
    {
        Count = 0;
    }
}

// 사용
int result = MathHelper.Add(5, 3);
double pi = MathHelper.Pi;

4.4 생성자와 소멸자

public class MyClass
{
    private string name;
    private int value;

    // 기본 생성자
    public MyClass()
    {
        name = "Default";
        value = 0;
    }

    // 매개변수 생성자
    public MyClass(string name, int value)
    {
        this.name = name;
        this.value = value;
    }

    // 생성자 체이닝
    public MyClass(string name) : this(name, 0)
    {
    }

    // 소멸자 (Finalizer)
    ~MyClass()
    {
        // 리소스 정리 (권장하지 않음, IDisposable 사용 권장)
    }
}

5. 상속과 다형성 (Inheritance and Polymorphism)

5.1 상속 (Inheritance)

// 기본 클래스
public class Animal
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Animal(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public virtual void MakeSound()
    {
        Console.WriteLine("Some sound");
    }

    public void Eat()
    {
        Console.WriteLine($"{Name} is eating.");
    }
}

// 파생 클래스
public class Dog : Animal
{
    public string Breed { get; set; }

    public Dog(string name, int age, string breed) 
        : base(name, age)
    {
        Breed = breed;
    }

    // 메서드 오버라이딩
    public override void MakeSound()
    {
        Console.WriteLine("Woof!");
    }

    // 새 메서드 추가
    public void Bark()
    {
        Console.WriteLine($"{Name} is barking!");
    }
}

// 사용
Dog dog = new Dog("Buddy", 3, "Golden Retriever");
dog.MakeSound();  // "Woof!"
dog.Eat();        // "Buddy is eating."

5.2 추상 클래스 (Abstract Classes)

// 추상 클래스
public abstract class Shape
{
    public abstract double GetArea();
    public abstract double GetPerimeter();

    public virtual void Draw()
    {
        Console.WriteLine("Drawing a shape");
    }
}

// 추상 클래스 구현
public class Circle : Shape
{
    public double Radius { get; set; }

    public Circle(double radius)
    {
        Radius = radius;
    }

    public override double GetArea()
    {
        return Math.PI * Radius * Radius;
    }

    public override double GetPerimeter()
    {
        return 2 * Math.PI * Radius;
    }
}

5.3 인터페이스 (Interfaces)

// 인터페이스 정의
public interface IFlyable
{
    void Fly();
    int MaxAltitude { get; set; }
}

public interface ISwimmable
{
    void Swim();
}

// 인터페이스 구현
public class Duck : IFlyable, ISwimmable
{
    public int MaxAltitude { get; set; } = 1000;

    public void Fly()
    {
        Console.WriteLine("Duck is flying");
    }

    public void Swim()
    {
        Console.WriteLine("Duck is swimming");
    }
}

// 인터페이스 사용
IFlyable flyable = new Duck();
flyable.Fly();

5.4 다형성 (Polymorphism)

// 다형성 예제
Animal[] animals = new Animal[]
{
    new Dog("Buddy", 3, "Golden Retriever"),
    new Cat("Whiskers", 2)
};

foreach (Animal animal in animals)
{
    animal.MakeSound();  // 각 객체의 오버라이딩된 메서드 호출
}

6. 제네릭 (Generics)

6.1 제네릭 클래스

// 제네릭 클래스
public class Box<T>
{
    private T item;

    public void SetItem(T item)
    {
        this.item = item;
    }

    public T GetItem()
    {
        return item;
    }
}

// 사용
Box<int> intBox = new Box<int>();
intBox.SetItem(42);
int value = intBox.GetItem();

Box<string> stringBox = new Box<string>();
stringBox.SetItem("Hello");
string text = stringBox.GetItem();

6.2 제네릭 메서드

public class Utility
{
    public static void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }

    public static T Max<T>(T a, T b) where T : IComparable<T>
    {
        return a.CompareTo(b) > 0 ? a : b;
    }
}

// 사용
int x = 5, y = 10;
Utility.Swap(ref x, ref y);  // x = 10, y = 5

string s1 = "apple", s2 = "banana";
string max = Utility.Max(s1, s2);  // "banana"

6.3 제네릭 제약 (Constraints)

// where 제약
public class Repository<T> where T : class
{
    private List<T> items = new List<T>();

    public void Add(T item)
    {
        items.Add(item);
    }
}

// 여러 제약
public class Processor<T> where T : class, new()
{
    public T Create()
    {
        return new T();
    }
}

// 인터페이스 제약
public class Sorter<T> where T : IComparable<T>
{
    public void Sort(List<T> list)
    {
        list.Sort();
    }
}

7. 델리게이트와 이벤트 (Delegates and Events)

7.1 델리게이트 (Delegates)

// 델리게이트 정의
public delegate void MyDelegate(string message);
public delegate int Calculate(int a, int b);

// 델리게이트 사용
public class Calculator
{
    public static int Add(int a, int b) => a + b;
    public static int Multiply(int a, int b) => a * b;
}

Calculate calc = Calculator.Add;
int result = calc(5, 3);  // 8

calc = Calculator.Multiply;
result = calc(5, 3);  // 15

// 멀티캐스트 델리게이트
MyDelegate del = PrintMessage;
del += PrintMessage2;
del("Hello");  // 두 메서드 모두 호출

void PrintMessage(string msg) => Console.WriteLine($"Message 1: {msg}");
void PrintMessage2(string msg) => Console.WriteLine($"Message 2: {msg}");

7.2 Func와 Action

// Func: 반환값이 있는 델리게이트
Func<int, int, int> add = (a, b) => a + b;
int sum = add(5, 3);  // 8

Func<string, int> getLength = s => s.Length;
int len = getLength("Hello");  // 5

// Action: 반환값이 없는 델리게이트
Action<string> print = s => Console.WriteLine(s);
print("Hello, World!");

Action<int, int> printSum = (a, b) => Console.WriteLine(a + b);
printSum(5, 3);  // 8 출력

7.3 이벤트 (Events)

// 이벤트 정의
public class Button
{
    public event EventHandler Clicked;

    public void Click()
    {
        Clicked?.Invoke(this, EventArgs.Empty);
    }
}

// 이벤트 구독
Button button = new Button();
button.Clicked += (sender, e) => Console.WriteLine("Button clicked!");
button.Click();  // "Button clicked!" 출력

// 커스텀 이벤트 인자
public class TemperatureChangedEventArgs : EventArgs
{
    public double OldTemperature { get; set; }
    public double NewTemperature { get; set; }
}

public class Thermometer
{
    public event EventHandler<TemperatureChangedEventArgs> TemperatureChanged;

    private double temperature;
    public double Temperature
    {
        get => temperature;
        set
        {
            if (temperature != value)
            {
                double oldTemp = temperature;
                temperature = value;
                TemperatureChanged?.Invoke(this, 
                    new TemperatureChangedEventArgs 
                    { 
                        OldTemperature = oldTemp, 
                        NewTemperature = value 
                    });
            }
        }
    }
}

8. LINQ (Language Integrated Query)

8.1 기본 LINQ 쿼리

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Where: 필터링
var evens = numbers.Where(n => n % 2 == 0);  // [2, 4, 6, 8, 10]

// Select: 변환
var squares = numbers.Select(n => n * n);  // [1, 4, 9, 16, ...]

// OrderBy: 정렬
var sorted = numbers.OrderBy(n => n);      // 오름차순
var desc = numbers.OrderByDescending(n => n); // 내림차순

// First/Last: 첫/마지막 요소
int first = numbers.First();              // 1
int last = numbers.Last();                // 10
int firstEven = numbers.First(n => n % 2 == 0); // 2

// Any/All: 조건 검사
bool hasEven = numbers.Any(n => n % 2 == 0);    // true
bool allPositive = numbers.All(n => n > 0);     // true

// Count: 개수
int count = numbers.Count();                     // 10
int evenCount = numbers.Count(n => n % 2 == 0);  // 5

// Sum/Average/Max/Min: 집계
int sum = numbers.Sum();                         // 55
double avg = numbers.Average();                  // 5.5
int max = numbers.Max();                         // 10
int min = numbers.Min();                         // 1

8.2 LINQ 쿼리 구문

List<Person> people = new List<Person>
{
    new Person { Name = "Alice", Age = 25 },
    new Person { Name = "Bob", Age = 30 },
    new Person { Name = "Charlie", Age = 25 }
};

// 쿼리 구문
var query = from p in people
            where p.Age > 25
            orderby p.Name
            select p.Name;

// 메서드 구문 (동일한 결과)
var query2 = people
    .Where(p => p.Age > 25)
    .OrderBy(p => p.Name)
    .Select(p => p.Name);

// Join
var joined = from p in people
             join c in cities on p.CityId equals c.Id
             select new { p.Name, c.CityName };

// GroupBy
var grouped = from p in people
             group p by p.Age into g
             select new { Age = g.Key, Count = g.Count() };

9. 예외 처리 (Exception Handling)

9.1 try-catch-finally

try
{
    int result = 10 / 0;  // DivideByZeroException 발생
}
catch (DivideByZeroException ex)
{
    Console.WriteLine($"Division by zero: {ex.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"General error: {ex.Message}");
}
finally
{
    Console.WriteLine("This always executes");
}

// 여러 예외 처리
try
{
    // 코드
}
catch (ArgumentNullException ex)
{
    // null 인자 예외 처리
}
catch (ArgumentException ex)
{
    // 인자 예외 처리
}
catch (Exception ex)
{
    // 기타 예외 처리
}

9.2 사용자 정의 예외

// 사용자 정의 예외 클래스
public class InvalidAgeException : Exception
{
    public InvalidAgeException(string message) : base(message)
    {
    }

    public InvalidAgeException(string message, Exception innerException) 
        : base(message, innerException)
    {
    }
}

// 예외 발생
public void SetAge(int age)
{
    if (age < 0 || age > 150)
    {
        throw new InvalidAgeException($"Invalid age: {age}");
    }
    this.age = age;
}

9.3 using 문 (IDisposable)

// using 문으로 리소스 자동 해제
using (var file = new StreamReader("file.txt"))
{
    string content = file.ReadToEnd();
}  // 자동으로 Dispose() 호출

// using 선언 (C# 8.0+)
using var file = new StreamReader("file.txt");
string content = file.ReadToEnd();
// 블록 종료 시 자동 Dispose

10. 비동기 프로그래밍 (Async/Await)

10.1 async/await 기본

// 비동기 메서드
public async Task<string> FetchDataAsync()
{
    await Task.Delay(1000);  // 1초 대기
    return "Data loaded";
}

// 사용
string data = await FetchDataAsync();
Console.WriteLine(data);

// 여러 비동기 작업
public async Task<string> FetchMultipleDataAsync()
{
    var task1 = FetchDataAsync();
    var task2 = FetchDataAsync();
    
    await Task.WhenAll(task1, task2);
    
    return $"{task1.Result} and {task2.Result}";
}

// 비동기 void (이벤트 핸들러에서만 사용)
public async void Button_Click(object sender, EventArgs e)
{
    await SomeAsyncMethod();
}

10.2 Task와 Task

// Task 생성
Task task = Task.Run(() => 
{
    Console.WriteLine("Running in background");
});

await task;

// Task<T> 반환
Task<int> taskWithResult = Task.Run(() => 
{
    return 42;
});

int result = await taskWithResult;

// 병렬 실행
var tasks = new List<Task<int>>();
for (int i = 0; i < 10; i++)
{
    int index = i;
    tasks.Add(Task.Run(() => index * 2));
}

int[] results = await Task.WhenAll(tasks);

11. 고급 기능

11.1 확장 메서드 (Extension Methods)

// 확장 메서드 정의
public static class StringExtensions
{
    public static bool IsValidEmail(this string email)
    {
        return email.Contains("@") && email.Contains(".");
    }

    public static string Reverse(this string str)
    {
        char[] chars = str.ToCharArray();
        Array.Reverse(chars);
        return new string(chars);
    }
}

// 사용
string email = "test@example.com";
bool isValid = email.IsValidEmail();  // true
string reversed = email.Reverse();    // "moc.elpmaxe@tset"

11.2 람다 표현식 (Lambda Expressions)

// 람다 표현식
Func<int, int> square = x => x * x;
int result = square(5);  // 25

// 여러 매개변수
Func<int, int, int> add = (x, y) => x + y;
int sum = add(3, 4);  // 7

// 문장 본문
Action<string> print = message => 
{
    Console.WriteLine($"Message: {message}");
};

// LINQ와 함께 사용
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evens = numbers.Where(n => n % 2 == 0);
var squares = numbers.Select(n => n * n);

11.3 null 조건부 연산자와 null 병합

// null 조건부 연산자
string str = null;
int? length = str?.Length;  // null (NullReferenceException 방지)

// null 병합 연산자
string name = null;
string displayName = name ?? "Unknown";  // "Unknown"

// null 병합 할당
string value = null;
value ??= "Default";  // value가 null이면 "Default" 할당

// 체이닝
string result = person?.Address?.City ?? "Unknown";

11.4 패턴 매칭 (Pattern Matching)

// is 패턴 (C# 7.0+)
object obj = 42;
if (obj is int i)
{
    Console.WriteLine($"Integer: {i}");
}

// switch 패턴 (C# 7.0+)
object value = 42;
switch (value)
{
    case int i when i > 0:
        Console.WriteLine($"Positive integer: {i}");
        break;
    case string s:
        Console.WriteLine($"String: {s}");
        break;
    case null:
        Console.WriteLine("Null");
        break;
    default:
        Console.WriteLine("Unknown");
        break;
}

// switch 표현식 (C# 8.0+)
string result = value switch
{
    int i when i > 0 => $"Positive: {i}",
    int i => $"Integer: {i}",
    string s => $"String: {s}",
    null => "Null",
    _ => "Unknown"
};

11.5 레코드 (Records) - C# 9.0+

// 레코드 정의
public record Person(string Name, int Age);

// 사용
var person1 = new Person("Alice", 25);
var person2 = new Person("Alice", 25);
bool equal = person1 == person2;  // true (값 기반 비교)

// with 표현식
var person3 = person1 with { Age = 26 };

// 레코드 상속
public record Student(string Name, int Age, string School) : Person(Name, Age);

11.6 init 접근자 - C# 9.0+

public class Person
{
    public string Name { get; init; }  // 객체 초기화 시에만 설정 가능
    public int Age { get; init; }
}

// 사용
var person = new Person { Name = "Alice", Age = 25 };
// person.Name = "Bob";  // 컴파일 오류 (init은 초기화 후 변경 불가)

12. 네임스페이스와 어셈블리

12.1 네임스페이스

// 네임스페이스 정의
namespace MyCompany.MyProject
{
    public class MyClass
    {
        // ...
    }
}

// 네임스페이스 별칭
using Project = MyCompany.MyProject;
Project.MyClass obj = new Project.MyClass();

// 전역 using (C# 10.0+)
global using System;
global using System.Collections.Generic;

12.2 어셈블리와 참조

// 다른 어셈블리의 클래스 사용
using System;
using System.Collections.Generic;

// NuGet 패키지 참조
// dotnet add package Newtonsoft.Json
using Newtonsoft.Json;

var json = JsonConvert.SerializeObject(new { Name = "Test" });

13. 속성과 리플렉션 (Attributes and Reflection)

13.1 속성 (Attributes)

// 속성 정의
[Serializable]
public class MyClass
{
    [Obsolete("Use NewMethod instead")]
    public void OldMethod() { }

    [Conditional("DEBUG")]
    public void DebugMethod() { }
}

// 사용자 정의 속성
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyAttribute : Attribute
{
    public string Description { get; set; }
}

[My(Description = "Test class")]
public class TestClass { }

13.2 리플렉션

// 타입 정보 가져오기
Type type = typeof(MyClass);

// 속성 정보
var attributes = type.GetCustomAttributes(typeof(MyAttribute), false);

// 메서드 정보
var methods = type.GetMethods();

// 인스턴스 생성
object instance = Activator.CreateInstance(type);

// 속성 설정
PropertyInfo prop = type.GetProperty("Name");
prop.SetValue(instance, "Test");

14. 결론

C#은 현대적인 객체지향 프로그래밍 언어로, 강력한 타입 시스템, 풍부한 표준 라이브러리, 그리고 지속적인 언어 개선을 통해 개발자에게 효율적인 개발 환경을 제공한다. 이 글에서 다룬 내용은 C#의 핵심 문법과 기능들이며, 실무에서 자주 사용되는 패턴들을 포함하고 있다. 각 기능을 실제 프로젝트에 적용하면서 더 깊이 있는 이해를 얻을 수 있다.