Ver3.0 ๐ C# ๋ง์คํฐ๋ก ๊ฐ๋ ์ฌ์

๐ C# ๋ง์คํฐ๋ก ๊ฐ๋ ์ฌ์
์ฃผ๋์ด ๊ฐ๋ฐ์๋ฅผ ์ํ ์๋ฒฝํ ํ์ต ๋ก๋๋งต
์๋ ! ๐ C# ๊ฐ๋ฐ์๊ฐ ๋๊ณ ์ถ์๋ฐ ์ด๋์๋ถํฐ ์์ํด์ผ ํ ์ง ๋ง๋งํ์ง? ๋๋ ์ฒ์์ ๊ทธ๋ฌ์ด. ์๋ง์ ๊ฐ์, ์ฑ , ํํ ๋ฆฌ์ผ ์ฌ์ด์์ ๊ธธ์ ์๊ณ ํค๋งธ๋ ๊ธฐ์ต์ด ์์ํด. ํ์ง๋ง ๊ฑฑ์ ๋ง! ์ค๋์ ๋ด๊ฐ ์ง์ ๊ฒช์ด๋ณธ ๊ฒฝํ๊ณผ ์๋ง์ ์ฃผ๋์ด ๊ฐ๋ฐ์๋ค์ ๋ฉํ ๋งํ๋ฉด์ ์ป์ ๋ ธํ์ฐ๋ฅผ ๋ฐํ์ผ๋ก, **๊ฐ์ฅ ํจ์จ์ ์ธ C# ํ์ต ๋ก๋๋งต**์ ์น๊ตฌ์ฒ๋ผ ํธํ๊ฒ ์๋ ค์ค๊ฒ.
์ด ๊ธ์ ๋จ์ํ "์ด๊ฒ ๊ณต๋ถํ๊ณ ์ ๊ฒ ๊ณต๋ถํ์ธ์"๊ฐ ์๋๋ผ, ์ค์ ๋ก ํ์ ์์ ํ์ํ ๊ฒ๋ค์ ์ค์ฌ์ผ๋ก ๊ตฌ์ฑํ์ด. ๊ทธ๋ฆฌ๊ณ ๊ฐ ๋จ๊ณ๋ง๋ค ์ ์ด๊ฑธ ๋ฐฐ์์ผ ํ๋์ง, ์ด๋ป๊ฒ ๊ณต๋ถํ๋ฉด ํจ๊ณผ์ ์ธ์ง๊น์ง ์์ธํ๊ฒ ๋ค๋ฃฐ ๊ฑฐ์ผ. ์ค๋น๋์ด? ๊ทธ๋ผ ์์ํด๋ณผ๊น! ๐ฏ
๐ฏ ์ C#์ ๋ฐฐ์์ผ ํ ๊น?
๋ณธ๊ฒฉ์ ์ธ ๋ก๋๋งต์ ๋ค์ด๊ฐ๊ธฐ ์ ์, ์ ๊น C#์ด ์ ์ข์ ์ ํ์ธ์ง ์ด์ผ๊ธฐํด๋ณผ๊ฒ. ์ด๊ฑด ๋จ์ํ ๋๊ธฐ๋ถ์ฌ๊ฐ ์๋๋ผ, ์์ผ๋ก์ ํ์ต ๋ฐฉํฅ์ ์ก๋ ๋ฐ ์ค์ํ ๋ถ๋ถ์ด๊ฑฐ๋ .
๐ผ ์ทจ์ ์์ฅ
C#์ ๊ตญ๋ด์ธ ๊ธฐ์ ์์ ๊พธ์คํ ์์๊ฐ ์์ด. ํนํ ๊ฒ์ ๊ฐ๋ฐ(Unity), ์ํฐํ๋ผ์ด์ฆ ์๋ฃจ์ , ํด๋ผ์ฐ๋ ์๋น์ค ๋ถ์ผ์์ ๊ฐ์ธ๋ฅผ ๋ณด์ด์ง. ์ค์ ๋ก ์ฌ๋์ธ, ์ก์ฝ๋ฆฌ์ ๊ฐ์ ๊ตฌ์ธ๊ตฌ์ง ์ฌ์ดํธ์์ 'C# ๊ฐ๋ฐ์'๋ก ๊ฒ์ํ๋ฉด ์์ฒ ๊ฐ์ ๊ณต๊ณ ๊ฐ ๋์.
๐ฎ ๋ค์ํ ํ์ฉ
์น ๊ฐ๋ฐ(ASP.NET), ๋ฐ์คํฌํฑ ์ฑ(WPF, WinForms), ๋ชจ๋ฐ์ผ(Xamarin), ๊ฒ์(Unity), ํด๋ผ์ฐ๋(Azure) ๋ฑ ์ ๋ง ๋ค์ํ ๋ถ์ผ์์ ์ฌ์ฉ๋ผ. ํ ์ธ์ด๋ก ์ฌ๋ฌ ํ๋ซํผ์ ์ปค๋ฒํ ์ ์๋ค๋ ๊ฑด ์์ฒญ๋ ์ฅ์ ์ด์ผ.
๐ ํ๋์ ์ธ ์ธ์ด
C#์ ๊ณ์ ์งํํ๊ณ ์์ด. ์ต์ ๋ฒ์ ์ธ C# 12๋ ํจํด ๋งค์นญ, ๋ ์ฝ๋ ํ์ , nullable ์ฐธ์กฐ ํ์ ๋ฑ ํ๋์ ์ธ ๊ธฐ๋ฅ๋ค์ ์ ๊ณตํด. Microsoft์ ๊ฐ๋ ฅํ ์ง์๋ ํฐ ๋ฉ๋ฆฌํธ์ง.
๐ฅ ์ปค๋ฎค๋ํฐ
Stack Overflow, GitHub, Reddit ๋ฑ์์ ํ๋ฐํ ์ปค๋ฎค๋ํฐ๊ฐ ํ์ฑ๋์ด ์์ด. ๋ฌธ์ ๊ฐ ์๊ฒผ์ ๋ ๋์๋ฐ๊ธฐ ์ฝ๊ณ , ์คํ์์ค ํ๋ก์ ํธ๋ ๋ง์์ ์ค์ ์ฝ๋๋ฅผ ๋ฐฐ์ฐ๊ธฐ ์ข์.
๐ 1๋จ๊ณ: ๊ธฐ์ด ๋ค์ง๊ธฐ (0-3๊ฐ์)
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์์ํด๋ณด์! ์ฒซ ๋ฒ์งธ ๋จ๊ณ๋ **ํํํ ๊ธฐ์ด๋ฅผ ์๋ ๊ฒ**์ด์ผ. ๋ง์ ์ฌ๋๋ค์ด ์ด ๋จ๊ณ๋ฅผ ๋์ถฉ ๋์ด๊ฐ๋๋ฐ, ์ด๊ฑด ์ ๋ง ํฐ ์ค์์ผ. ๊ธฐ์ด๊ฐ ํผํผํด์ผ ๋์ค์ ๋ณต์กํ ๊ฐ๋ ๋ ์ฝ๊ฒ ์ดํดํ ์ ์๊ฑฐ๋ .
๐ค ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ณธ ๊ฐ๋
๋ณ์์ ๋ฐ์ดํฐ ํ์ ๐ฒ
C#์ ์ ์ ํ์ ์ธ์ด์ผ. ์ฆ, ๋ณ์๋ฅผ ์ ์ธํ ๋ ํ์ ์ ๋ช ์ํด์ผ ํด. ์ฒ์์ ๊ท์ฐฎ์ ์ ์์ง๋ง, ์ด๊ฒ ๋์ค์ ๋ฒ๊ทธ๋ฅผ ์ค์ฌ์ฃผ๋ ๊ฐ๋ ฅํ ๋๊ตฌ๊ฐ ๋ผ.
// ๊ธฐ๋ณธ ๋ฐ์ดํฐ ํ์
๋ค
int age = 25; // ์ ์
double price = 19.99; // ์ค์
string name = "๊น๊ฐ๋ฐ"; // ๋ฌธ์์ด
bool isStudent = true; // ๋ถ๋ฆฌ์ธ
char grade = 'A'; // ๋ฌธ์
// var ํค์๋ (ํ์
์ถ๋ก )
var city = "์์ธ"; // ์ปดํ์ผ๋ฌ๊ฐ ์๋์ผ๋ก string์ผ๋ก ์ธ์
์ ์ด๋ฌธ๊ณผ ๋ฐ๋ณต๋ฌธ ๐
ํ๋ก๊ทธ๋จ์ ํ๋ฆ์ ์ ์ดํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์์ผ ํด. if-else, switch, for, while, foreach ๋ฑ์ด ์ฌ๊ธฐ์ ์ํด.
// if-else ๋ฌธ
if (age >= 20)
{
Console.WriteLine("์ฑ์ธ์
๋๋ค");
}
else
{
Console.WriteLine("๋ฏธ์ฑ๋
์์
๋๋ค");
}
// switch ๋ฌธ (C# 8.0 ์ด์์ ํจํด ๋งค์นญ)
string result = age switch
{
< 13 => "์ด๋ฆฐ์ด",
< 20 => "์ฒญ์๋
",
_ => "์ฑ์ธ"
};
// foreach ๋ฐ๋ณต๋ฌธ
string[] fruits = { "์ฌ๊ณผ", "๋ฐ๋๋", "์ค๋ ์ง" };
foreach (var fruit in fruits)
{
Console.WriteLine(fruit);
}
๐จ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ (OOP)
C#์ ํต์ฌ์ด์ ๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ์ด์ผ. OOP๋ฅผ ์ ๋๋ก ์ดํดํ์ง ๋ชปํ๋ฉด C#์ ์ ๋๋ก ํ์ฉํ ์ ์์ด. ์ฒ์ฒํ, ํ์คํ๊ฒ ์ตํ์!
1๏ธโฃ ํด๋์ค์ ๊ฐ์ฒด
ํด๋์ค๋ ์ค๊ณ๋, ๊ฐ์ฒด๋ ๊ทธ ์ค๊ณ๋๋ก ๋ง๋ ์ค์ ์ ํ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ.
// ํด๋์ค ์ ์
public class Student
{
// ํ๋ (๋ฉค๋ฒ ๋ณ์)
private string name;
private int age;
// ํ๋กํผํฐ (C#์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ!)
public string Name
{
get { return name; }
set { name = value; }
}
// ์๋ ํ๋กํผํฐ (๋ ๊ฐ๋จํ๊ฒ)
public int Age { get; set; }
// ์์ฑ์
public Student(string name, int age)
{
this.name = name;
this.age = age;
}
// ๋ฉ์๋
public void Introduce()
{
Console.WriteLine($"์๋
ํ์ธ์, {name}์
๋๋ค. {age}์ด์ด์์.");
}
}
// ๊ฐ์ฒด ์์ฑ ๋ฐ ์ฌ์ฉ
Student student = new Student("๊น์ฒ ์", 20);
student.Introduce();
2๏ธโฃ ์บก์ํ (Encapsulation)
๋ฐ์ดํฐ๋ฅผ ์จ๊ธฐ๊ณ ํ์ํ ๊ฒ๋ง ๊ณต๊ฐํ๋ ๊ฑฐ์ผ. private, public, protected ๊ฐ์ ์ ๊ทผ ์ ํ์๋ฅผ ์ฌ์ฉํด.
3๏ธโฃ ์์ (Inheritance)
๊ธฐ์กด ํด๋์ค์ ๊ธฐ๋ฅ์ ๋ฌผ๋ ค๋ฐ์ ์๋ก์ด ํด๋์ค๋ฅผ ๋ง๋๋ ๊ฑฐ์ผ. ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ์ด ์์ฒญ ์ข์์ ธ.
// ๋ถ๋ชจ ํด๋์ค
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public virtual void Introduce()
{
Console.WriteLine($"์ ๋ {Name}์
๋๋ค.");
}
}
// ์์ ํด๋์ค
public class Developer : Person
{
public string Language { get; set; }
// ๋ฉ์๋ ์ค๋ฒ๋ผ์ด๋ฉ
public override void Introduce()
{
base.Introduce(); // ๋ถ๋ชจ ๋ฉ์๋ ํธ์ถ
Console.WriteLine($"{Language} ๊ฐ๋ฐ์์
๋๋ค.");
}
}
4๏ธโฃ ๋คํ์ฑ (Polymorphism)
๊ฐ์ ์ธํฐํ์ด์ค๋ก ๋ค๋ฅธ ๋์์ ํ๊ฒ ๋ง๋๋ ๊ฑฐ์ผ. ์ธํฐํ์ด์ค์ ์ถ์ ํด๋์ค๊ฐ ํต์ฌ์ด์ง.
// ์ธํฐํ์ด์ค ์ ์
public interface IDrawable
{
void Draw();
}
// ์ฌ๋ฌ ํด๋์ค๊ฐ ๊ฐ์ ์ธํฐํ์ด์ค ๊ตฌํ
public class Circle : IDrawable
{
public void Draw()
{
Console.WriteLine("์์ ๊ทธ๋ฆฝ๋๋ค โญ");
}
}
public class Square : IDrawable
{
public void Draw()
{
Console.WriteLine("์ฌ๊ฐํ์ ๊ทธ๋ฆฝ๋๋ค โฌ");
}
}
// ๋คํ์ฑ ํ์ฉ
List<IDrawable> shapes = new List<IDrawable>
{
new Circle(),
new Square()
};
foreach (var shape in shapes)
{
shape.Draw(); // ๊ฐ ๊ฐ์ฒด์ Draw ๋ฉ์๋๊ฐ ํธ์ถ๋จ
}
๐ฆ ์ปฌ๋ ์ ๊ณผ ์ ๋ค๋ฆญ
๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์์ผ ํด. List, Dictionary, Queue, Stack ๋ฑ์ ์ปฌ๋ ์ ๊ณผ ์ ๋ค๋ฆญ์ ์ค๋ฌด์์ ์ ๋ง ๋ง์ด ์ฌ์ฉ๋ผ.
List<T>
๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ์ปฌ๋ ์ . ๋์ ๋ฐฐ์ด์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ.
List<string> names = new List<string>();
names.Add("๊น์ฒ ์");
names.Add("์ด์ํฌ");
Dictionary<K,V>
ํค-๊ฐ ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅ. ๋น ๋ฅธ ๊ฒ์์ด ํ์ํ ๋ ์ต๊ณ !
Dictionary<string, int> scores = new();
scores["๊น์ฒ ์"] = 95;
scores["์ด์ํฌ"] = 88;
์ ๋ค๋ฆญ์ ํ โก
์ ๋ค๋ฆญ์ ์ฌ์ฉํ๋ฉด ํ์ ์์ ์ฑ์ ์ ์งํ๋ฉด์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ฝ๋๋ฅผ ๋ง๋ค ์ ์์ด.
// ์ ๋ค๋ฆญ ํด๋์ค
public class Box<T>
{
private T item;
public void Pack(T item)
{
this.item = item;
}
public T Unpack()
{
return item;
}
}
// ์ฌ์ฉ
Box<string> stringBox = new Box<string>();
stringBox.Pack("์ ๋ฌผ");
Box<int> intBox = new Box<int>();
intBox.Pack(100);
๐ 1๋จ๊ณ ํ์ต ์ ๋ต
๐ ์ถ์ฒ ํ์ต ์๋ฃ
โข Microsoft Learn์ C# ๊ณต์ ๋ฌธ์ (๋ฌด๋ฃ, ํ๊ธ ์ง์)
โข "C# ํ๋ก๊ทธ๋๋ฐ" (์ด๊ฒ์ด C#์ด๋ค) - ๋ฐ์ํ ์
โข YouTube: ์ฝ๋ฉ์ ํ, ๋๋ฆผ์ฝ๋ฉ ๋ฑ์ C# ๊ธฐ์ด ๊ฐ์
โข ์ฌ๋ฅ๋ท์์ C# ๋ฉํ ๋ง ์ฐพ์๋ณด๊ธฐ (์ค์๊ฐ ์ง๋ฌธ ๊ฐ๋ฅ!)
๐ 2๋จ๊ณ: ์ค๊ธ์ผ๋ก ๋์ฝ (3-6๊ฐ์)
๊ธฐ์ด๋ฅผ ํํํ ๋ค์ก๋ค๋ฉด, ์ด์ **์ค๋ฌด์์ ์ ๋ง ๋ง์ด ์ฌ์ฉํ๋ ์ค๊ธ ๊ฐ๋ ๋ค**์ ๋ฐฐ์ธ ์ฐจ๋ก์ผ. ์ด ๋จ๊ณ๋ถํฐ๋ ๋จ์ํ ๋ฌธ๋ฒ์ ์๋ ๊ฒ์ ๋์ด์, "์ ์ด๋ ๊ฒ ์ฝ๋ฉํด์ผ ํ๋๊ฐ"๋ฅผ ์ดํดํ๋ ๊ฒ ์ค์ํด.
๐ง LINQ (Language Integrated Query)
LINQ๋ C#์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ ์ค ํ๋์ผ. ๋ฐ์ดํฐ๋ฅผ ์ฟผ๋ฆฌํ๊ณ ์กฐ์ํ๋ ๊ฑธ ์์ฒญ ์ฝ๊ฒ ๋ง๋ค์ด์ค. SQL์ ์๊ณ ์๋ค๋ฉด ๋ ์ฝ๊ฒ ์ดํดํ ์ ์์ ๊ฑฐ์ผ.
LINQ์ ๋ ๊ฐ์ง ๋ฌธ๋ฒ
์ฟผ๋ฆฌ ๊ตฌ๋ฌธ(Query Syntax)๊ณผ ๋ฉ์๋ ๊ตฌ๋ฌธ(Method Syntax)์ด ์์ด. ๋ ๋ค ์์๋๋ฉด ์ข์ง๋ง, ์ค๋ฌด์์๋ ๋ฉ์๋ ๊ตฌ๋ฌธ์ ๋ ๋ง์ด ์ฌ์ฉํด.
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// ์ฟผ๋ฆฌ ๊ตฌ๋ฌธ
var evenQuery = from num in numbers
where num % 2 == 0
select num;
// ๋ฉ์๋ ๊ตฌ๋ฌธ (๋ ๋ง์ด ์ฌ์ฉ๋จ)
var evenMethod = numbers.Where(num => num % 2 == 0);
// ๋ณต์กํ ์์
var result = numbers
.Where(n => n > 3) // 3๋ณด๋ค ํฐ ์
.Select(n => n * 2) // 2๋ฐฐ๋ก ๋ง๋ค๊ธฐ
.OrderByDescending(n => n) // ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ
.Take(3); // ์์ 3๊ฐ๋ง
foreach (var num in result)
{
Console.WriteLine(num); // 20, 18, 16
}
๐ฏ LINQ ํต์ฌ ๋ฉ์๋๋ค
Where ํํฐ๋ง
Select ๋ณํ
OrderBy/OrderByDescending ์ ๋ ฌ
GroupBy ๊ทธ๋ฃนํ
Join ์กฐ์ธ
First/FirstOrDefault ์ฒซ ๋ฒ์งธ ์์
Any/All ์กฐ๊ฑด ํ์ธ
Count/Sum/Average ์ง๊ณ
// ์ค์ ์์ : ํ์ ์ฑ์ ์ฒ๋ฆฌ
public class Student
{
public string Name { get; set; }
public int Score { get; set; }
public string Department { get; set; }
}
List<Student> students = new List<Student>
{
new Student { Name = "๊น์ฒ ์", Score = 85, Department = "์ปด๊ณต" },
new Student { Name = "์ด์ํฌ", Score = 92, Department = "์ ์" },
new Student { Name = "๋ฐ๋ฏผ์", Score = 78, Department = "์ปด๊ณต" },
new Student { Name = "์ ์์ง", Score = 95, Department = "์ปด๊ณต" }
};
// ์ปด๊ณต๊ณผ ํ์ ์ค 80์ ์ด์์ธ ํ์๋ค์ ํ๊ท
var avgScore = students
.Where(s => s.Department == "์ปด๊ณต" && s.Score >= 80)
.Average(s => s.Score);
Console.WriteLine($"ํ๊ท : {avgScore}"); // 90
// ํ๊ณผ๋ณ ํ๊ท ์ ์
var deptAvg = students
.GroupBy(s => s.Department)
.Select(g => new
{
Department = g.Key,
Average = g.Average(s => s.Score)
});
foreach (var dept in deptAvg)
{
Console.WriteLine($"{dept.Department}: {dept.Average}");
}
โก ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ (async/await)
ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ํ์์ผ. ํนํ ์น API ํธ์ถ, ํ์ผ I/O, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ๋ฑ์์ ๋ฐ๋์ ์ฌ์ฉํด์ผ ํด.
์ ๋น๋๊ธฐ๊ฐ ํ์ํ ๊น? ๐ค
๋๊ธฐ ๋ฐฉ์์ ํ ์์ ์ด ๋๋ ๋๊น์ง ๋ค์ ์์ ์ ๊ธฐ๋ค๋ ค์ผ ํด. ๋ง์ฝ ๋คํธ์ํฌ ์์ฒญ์ด 5์ด ๊ฑธ๋ฆฐ๋ค๋ฉด? ๊ทธ 5์ด ๋์ ํ๋ก๊ทธ๋จ์ด ๋ฉ์ถฐ์๋ ๊ฑฐ์ง. ๋น๋๊ธฐ๋ฅผ ์ฌ์ฉํ๋ฉด ๊ธฐ๋ค๋ฆฌ๋ ๋์ ๋ค๋ฅธ ์์ ์ ํ ์ ์์ด!
// ๋๊ธฐ ๋ฐฉ์ (๋์ ์)
public void DownloadFile()
{
// ํ์ผ ๋ค์ด๋ก๋ ์ค... (5์ด ์์)
// ์ด ๋์ ํ๋ก๊ทธ๋จ์ด ๋ฉ์ถค!
Thread.Sleep(5000);
Console.WriteLine("๋ค์ด๋ก๋ ์๋ฃ");
}
// ๋น๋๊ธฐ ๋ฐฉ์ (์ข์ ์)
public async Task DownloadFileAsync()
{
// ํ์ผ ๋ค์ด๋ก๋ ์ค... (5์ด ์์)
// ํ์ง๋ง ๋ค๋ฅธ ์์
๊ฐ๋ฅ!
await Task.Delay(5000);
Console.WriteLine("๋ค์ด๋ก๋ ์๋ฃ");
}
// ์ฌ์ฉ
await DownloadFileAsync();
Console.WriteLine("๋ค๋ฅธ ์์
์งํ ์ค...");
async/await์ ํต์ฌ ๊ท์น ๐
1. async ๋ฉ์๋๋ Task ๋๋ Task<T>๋ฅผ ๋ฐํํด์ผ ํด
2. await๋ async ๋ฉ์๋ ์์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ
3. ๋ฉ์๋ ์ด๋ฆ ๋์ Async๋ฅผ ๋ถ์ด๋ ๊ฒ ๊ด๋ก
4. async void๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์์๋ง ์ฌ์ฉ
// ์ค์ ์์ : HTTP ์์ฒญ
public class ApiService
{
private readonly HttpClient _httpClient = new HttpClient();
// ๋น๋๊ธฐ๋ก ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
public async Task<string> GetDataAsync(string url)
{
try
{
// await๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ต์ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์ค๋ ๋๊ฐ ๋ธ๋ก๋์ง ์์
HttpResponseMessage response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
return content;
}
catch (HttpRequestException e)
{
Console.WriteLine($"์๋ฌ ๋ฐ์: {e.Message}");
return null;
}
}
// ์ฌ๋ฌ ์์ฒญ์ ๋์์ ์ฒ๋ฆฌ
public async Task<List<string>> GetMultipleDataAsync(List<string> urls)
{
// Task.WhenAll์ ์ฌ์ฉํ๋ฉด ๋ชจ๋ ์์ฒญ์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌ
var tasks = urls.Select(url => GetDataAsync(url));
var results = await Task.WhenAll(tasks);
return results.ToList();
}
}
// ์ฌ์ฉ ์์
var service = new ApiService();
var data = await service.GetDataAsync("https://api.example.com/data");
Console.WriteLine(data);
๐ญ ๋ธ๋ฆฌ๊ฒ์ดํธ์ ์ด๋ฒคํธ
๋ธ๋ฆฌ๊ฒ์ดํธ๋ ๋ฉ์๋๋ฅผ ๋ณ์์ฒ๋ผ ๋ค๋ฃฐ ์ ์๊ฒ ํด์ฃผ๋ ๊ฑฐ์ผ. ์ด๋ฒคํธ๋ ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์ด์ง ํจํด์ด๊ณ . ํนํ UI ํ๋ก๊ทธ๋๋ฐ์ด๋ ์ด๋ฒคํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ์์ ํ์์ ์ด์ผ.
๋ธ๋ฆฌ๊ฒ์ดํธ ๊ธฐ์ด
๋ธ๋ฆฌ๊ฒ์ดํธ๋ ํจ์ ํฌ์ธํฐ์ ์์ ํ ๋ฒ์ ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ. C#์์๋ Func, Action, Predicate ๊ฐ์ ๋ด์ฅ ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ๋ง์ด ์ฌ์ฉํด.
// ๋ธ๋ฆฌ๊ฒ์ดํธ ์ ์ธ
public delegate int Calculate(int x, int y);
// ๋ธ๋ฆฌ๊ฒ์ดํธ ์ฌ์ฉ
public class Calculator
{
public int Add(int x, int y) => x + y;
public int Subtract(int x, int y) => x - y;
public int Multiply(int x, int y) => x * y;
}
// ์ฌ์ฉ ์์
Calculator calc = new Calculator();
Calculate operation;
operation = calc.Add;
Console.WriteLine(operation(5, 3)); // 8
operation = calc.Multiply;
Console.WriteLine(operation(5, 3)); // 15
// ๋ด์ฅ ๋ธ๋ฆฌ๊ฒ์ดํธ ์ฌ์ฉ (๋ ๊ฐ๋จ!)
Func<int, int, int> add = (x, y) => x + y;
Action<string> print = message => Console.WriteLine(message);
Predicate<int> isEven = num => num % 2 == 0;
Console.WriteLine(add(10, 20)); // 30
print("์๋
ํ์ธ์!"); // ์๋
ํ์ธ์!
Console.WriteLine(isEven(4)); // True
์ด๋ฒคํธ ํจํด ๐ช
์ด๋ฒคํธ๋ ๋ฐํ-๊ตฌ๋ (Publish-Subscribe) ํจํด์ ๊ตฌํํด. ํ ๊ฐ์ฒด๊ฐ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๋ฉด, ๊ตฌ๋ ํ ๋ค๋ฅธ ๊ฐ์ฒด๋ค์ด ์๋ฆผ์ ๋ฐ๋ ๊ฑฐ์ง.
// ์ด๋ฒคํธ ๋ฐํ์
public class Button
{
// ์ด๋ฒคํธ ์ ์ธ
public event EventHandler Clicked;
// ์ด๋ฒคํธ ๋ฐ์ ๋ฉ์๋
public void Click()
{
Console.WriteLine("๋ฒํผ์ด ํด๋ฆญ๋์์ต๋๋ค!");
// ์ด๋ฒคํธ ๋ฐ์ (๊ตฌ๋
์๋ค์๊ฒ ์๋ฆผ)
Clicked?.Invoke(this, EventArgs.Empty);
}
}
// ์ด๋ฒคํธ ๊ตฌ๋
์
public class Logger
{
public void OnButtonClicked(object sender, EventArgs e)
{
Console.WriteLine("๋ก๊ทธ: ๋ฒํผ ํด๋ฆญ ์ด๋ฒคํธ ๊ฐ์ง๋จ");
}
}
// ์ฌ์ฉ
Button button = new Button();
Logger logger = new Logger();
// ์ด๋ฒคํธ ๊ตฌ๋
button.Clicked += logger.OnButtonClicked;
// ๋๋ค์์ผ๋ก๋ ๊ตฌ๋
๊ฐ๋ฅ
button.Clicked += (sender, e) =>
{
Console.WriteLine("์ถ๊ฐ ์ฒ๋ฆฌ: ํด๋ฆญ ํ์ ์ฆ๊ฐ");
};
// ๋ฒํผ ํด๋ฆญ
button.Click();
// ์ถ๋ ฅ:
// ๋ฒํผ์ด ํด๋ฆญ๋์์ต๋๋ค!
// ๋ก๊ทธ: ๋ฒํผ ํด๋ฆญ ์ด๋ฒคํธ ๊ฐ์ง๋จ
// ์ถ๊ฐ ์ฒ๋ฆฌ: ํด๋ฆญ ํ์ ์ฆ๊ฐ
๐๏ธ ํ์ผ I/O์ ์ง๋ ฌํ
๋ฐ์ดํฐ๋ฅผ ํ์ผ์ ์ ์ฅํ๊ณ ์ฝ์ด์ค๋ ๊ฑด ์ค๋ฌด์์ ์ ๋ง ์์ฃผ ํ๋ ์์ ์ด์ผ. JSON, XML ๊ฐ์ ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ๊ฒ๋ ๋ฐฐ์์ผ ํด.
ํ์ผ ์ฝ๊ธฐ/์ฐ๊ธฐ
// ํ
์คํธ ํ์ผ ์ฐ๊ธฐ
File.WriteAllText("test.txt", "์๋
ํ์ธ์");
// ํ
์คํธ ํ์ผ ์ฝ๊ธฐ
string content = File.ReadAllText("test.txt");
// ์ฌ๋ฌ ์ค ์ฐ๊ธฐ
string[] lines = { "์ฒซ ์ค", "๋์งธ ์ค", "์
์งธ ์ค" };
File.WriteAllLines("lines.txt", lines);
JSON ์ง๋ ฌํ
using System.Text.Json;
// ๊ฐ์ฒด๋ฅผ JSON์ผ๋ก
var person = new { Name = "๊น์ฒ ์", Age = 25 };
string json = JsonSerializer.Serialize(person);
// JSON์ ๊ฐ์ฒด๋ก
var restored = JsonSerializer.Deserialize<Person>(json);
// ์ค์ ์์ : ์ค์ ํ์ผ ๊ด๋ฆฌ
public class AppSettings
{
public string Theme { get; set; }
public int FontSize { get; set; }
public bool AutoSave { get; set; }
}
public class SettingsManager
{
private const string SettingsFile = "settings.json";
// ์ค์ ์ ์ฅ
public async Task SaveSettingsAsync(AppSettings settings)
{
var options = new JsonSerializerOptions
{
WriteIndented = true // ๋ณด๊ธฐ ์ข๊ฒ ํฌ๋งทํ
};
string json = JsonSerializer.Serialize(settings, options);
await File.WriteAllTextAsync(SettingsFile, json);
}
// ์ค์ ๋ถ๋ฌ์ค๊ธฐ
public async Task<AppSettings> LoadSettingsAsync()
{
if (!File.Exists(SettingsFile))
{
return new AppSettings
{
Theme = "Light",
FontSize = 12,
AutoSave = true
};
}
string json = await File.ReadAllTextAsync(SettingsFile);
return JsonSerializer.Deserialize<AppSettings>(json);
}
}
// ์ฌ์ฉ
var manager = new SettingsManager();
var settings = await manager.LoadSettingsAsync();
settings.Theme = "Dark";
await manager.SaveSettingsAsync(settings);
๐ 2๋จ๊ณ ํ์ต ์ ๋ต
๐ ์ถ์ฒ ํ์ต ๋ฐฉ๋ฒ
โข ํ๋ก์ ํธ ๊ธฐ๋ฐ ํ์ต: ๊ฐ๋จํ ์ฝ์ ์ฑ๋ถํฐ ์์ํด์ ์ ์ ๋ณต์กํ ํ๋ก์ ํธ๋ก
โข ์ฝ๋ ๋ฆฌ๋ทฐ: GitHub์์ ์คํ์์ค C# ํ๋ก์ ํธ ์ฝ๋ ์ฝ์ด๋ณด๊ธฐ
โข ๋ฌธ์ ํด๊ฒฐ: LeetCode, ํ๋ก๊ทธ๋๋จธ์ค์์ C#๋ก ์๊ณ ๋ฆฌ์ฆ ๋ฌธ์ ํ๊ธฐ
โข ๋ฉํ ๋ง: ์ฌ๋ฅ๋ท์์ ๊ฒฝํ ๋ง์ ๊ฐ๋ฐ์์๊ฒ ์ฝ๋ ๋ฆฌ๋ทฐ ๋ฐ๊ธฐ
โข ์ปค๋ฎค๋ํฐ: C# ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํด์ ์ง๋ฌธํ๊ณ ๋ต๋ณํ๊ธฐ
2. ๊ฐ๋จํ ์ฑํ ํ๋ก๊ทธ๋จ (๋คํธ์ํน, ๋น๋๊ธฐ)
3. ํ์ผ ๊ด๋ฆฌ ๋๊ตฌ (ํ์ผ I/O, LINQ)
4. ๋ ์จ ์ ๋ณด ์ฑ (API ํธ์ถ, JSON ํ์ฑ)
5. ๊ฐ๋จํ ๊ฒ์ (์ด๋ฒคํธ, ๋ธ๋ฆฌ๊ฒ์ดํธ)
๐ผ 3๋จ๊ณ: ์ค์ ํ๋ก์ ํธ (6-12๊ฐ์)
์ด์ ์ง์ง ๊ฐ๋ฐ์์ฒ๋ผ ์ผํ ์ค๋น๋ฅผ ํด์ผ ํด! ์ด ๋จ๊ณ์์๋ **์ค๋ฌด์์ ์ฌ์ฉํ๋ ํ๋ ์์ํฌ์ ๋๊ตฌ๋ค**์ ๋ฐฐ์ฐ๊ณ , ์ค์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ณผ ๊ฑฐ์ผ.
๐ ASP.NET Core ์น ๊ฐ๋ฐ
C# ๋ฐฑ์๋ ๊ฐ๋ฐ์ ํต์ฌ์ด์ผ. ASP.NET Core๋ ํฌ๋ก์ค ํ๋ซํผ์ ์ง์ํ๊ณ , ์ฑ๋ฅ๋ ๋ฐ์ด๋์ ๋ง์ ๊ธฐ์ ์์ ์ฌ์ฉํ๊ณ ์์ด.
ASP.NET Core์ ์ฃผ์ ๊ฐ๋
โข MVC ํจํด: Model-View-Controller ์ํคํ
์ฒ
โข Web API: RESTful API ๊ฐ๋ฐ
โข Middleware: ์์ฒญ/์๋ต ํ์ดํ๋ผ์ธ
โข Dependency Injection: ์์กด์ฑ ์ฃผ์
โข Entity Framework Core: ORM (๋ฐ์ดํฐ๋ฒ ์ด์ค ์์
)
// ๊ฐ๋จํ Web API ์ปจํธ๋กค๋ฌ
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
// ์์กด์ฑ ์ฃผ์
public ProductsController(IProductService productService)
{
_productService = productService;
}
// GET: api/products
[HttpGet]
public async Task<ActionResult<List<Product>>> GetProducts()
{
var products = await _productService.GetAllProductsAsync();
return Ok(products);
}
// GET: api/products/5
[HttpGet("{id}")]
public async Task<ActionResult<Product>> GetProduct(int id)
{
var product = await _productService.GetProductByIdAsync(id);
if (product == null)
{
return NotFound();
}
return Ok(product);
}
// POST: api/products
[HttpPost]
public async Task<ActionResult<Product>> CreateProduct(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var created = await _productService.CreateProductAsync(product);
return CreatedAtAction(nameof(GetProduct), new { id = created.Id }, created);
}
// PUT: api/products/5
[HttpPut("{id}")]
public async Task<IActionResult> UpdateProduct(int id, Product product)
{
if (id != product.Id)
{
return BadRequest();
}
await _productService.UpdateProductAsync(product);
return NoContent();
}
// DELETE: api/products/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
await _productService.DeleteProductAsync(id);
return NoContent();
}
}
Entity Framework Core๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ค๋ฃจ๊ธฐ ๐๏ธ
EF Core๋ C#์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ค๋ฃจ๋ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ORM์ด์ผ. SQL์ ์ง์ ์ฐ์ง ์๊ณ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ํ ์ ์์ด.
// DbContext ์ ์
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// ๊ด๊ณ ์ค์
modelBuilder.Entity<Product>()
.HasOne(p => p.Category)
.WithMany(c => c.Products)
.HasForeignKey(p => p.CategoryId);
// ์ธ๋ฑ์ค ์ค์
modelBuilder.Entity<Product>()
.HasIndex(p => p.Name);
}
}
// ์ํฐํฐ ํด๋์ค
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int CategoryId { get; set; }
// ๋ค๋น๊ฒ์ด์
ํ๋กํผํฐ
public Category Category { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
// ์ปฌ๋ ์
๋ค๋น๊ฒ์ด์
ํ๋กํผํฐ
public List<Product> Products { get; set; }
}
// ์๋น์ค ๋ ์ด์ด
public class ProductService : IProductService
{
private readonly AppDbContext _context;
public ProductService(AppDbContext context)
{
_context = context;
}
public async Task<List<Product>> GetAllProductsAsync()
{
return await _context.Products
.Include(p => p.Category) // ๊ด๋ จ ๋ฐ์ดํฐ ํฌํจ
.ToListAsync();
}
public async Task<Product> GetProductByIdAsync(int id)
{
return await _context.Products
.Include(p => p.Category)
.FirstOrDefaultAsync(p => p.Id == id);
}
public async Task<Product> CreateProductAsync(Product product)
{
_context.Products.Add(product);
await _context.SaveChangesAsync();
return product;
}
public async Task UpdateProductAsync(Product product)
{
_context.Entry(product).State = EntityState.Modified;
await _context.SaveChangesAsync();
}
public async Task DeleteProductAsync(int id)
{
var product = await _context.Products.FindAsync(id);
if (product != null)
{
_context.Products.Remove(product);
await _context.SaveChangesAsync();
}
}
}
๐ฎ Unity๋ก ๊ฒ์ ๊ฐ๋ฐ
C#์ ๋ฐฐ์ฐ๋ ๋ง์ ์ฌ๋๋ค์ด ๊ฒ์ ๊ฐ๋ฐ์ ๊ด์ฌ์ด ์์ด. Unity๋ C#์ ์คํฌ๋ฆฝํ ์ธ์ด๋ก ์ฌ์ฉํ๋ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ๊ฒ์ ์์ง์ด์ผ.
Unity C# ์คํฌ๋ฆฝํ ๊ธฐ์ด
Unity์์๋ MonoBehaviour๋ฅผ ์์๋ฐ์ ๊ฒ์ ์ค๋ธ์ ํธ์ ๋์์ ์ ์ดํด. Start(), Update() ๊ฐ์ ์๋ช ์ฃผ๊ธฐ ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ํด์ ์ฌ์ฉํ์ง.
using UnityEngine;
// ํ๋ ์ด์ด ์ปจํธ๋กค๋ฌ ์์
public class PlayerController : MonoBehaviour
{
// Inspector์์ ์ค์ ๊ฐ๋ฅํ ๋ณ์
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float jumpForce = 10f;
private Rigidbody2D rb;
private bool isGrounded;
// ์ด๊ธฐํ
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// ๋งค ํ๋ ์๋ง๋ค ํธ์ถ
void Update()
{
// ์
๋ ฅ ์ฒ๋ฆฌ
float horizontal = Input.GetAxis("Horizontal");
Move(horizontal);
// ์ ํ
if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
Jump();
}
}
void Move(float direction)
{
// ์ด๋
Vector2 movement = new Vector2(direction * moveSpeed, rb.velocity.y);
rb.velocity = movement;
// ์บ๋ฆญํฐ ๋ฐฉํฅ ์ ํ
if (direction != 0)
{
transform.localScale = new Vector3(
Mathf.Sign(direction),
1,
1
);
}
}
void Jump()
{
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
isGrounded = false;
}
// ์ถฉ๋ ๊ฐ์ง
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
}
// ์ AI ์์
public class EnemyAI : MonoBehaviour
{
[SerializeField] private Transform player;
[SerializeField] private float detectionRange = 5f;
[SerializeField] private float attackRange = 1.5f;
[SerializeField] private float moveSpeed = 3f;
private enum State { Idle, Chase, Attack }
private State currentState = State.Idle;
void Update()
{
float distanceToPlayer = Vector2.Distance(transform.position, player.position);
// ์ํ ์ ํ
switch (currentState)
{
case State.Idle:
if (distanceToPlayer < detectionRange)
{
currentState = State.Chase;
}
break;
case State.Chase:
if (distanceToPlayer < attackRange)
{
currentState = State.Attack;
}
else if (distanceToPlayer > detectionRange)
{
currentState = State.Idle;
}
else
{
ChasePlayer();
}
break;
case State.Attack:
if (distanceToPlayer > attackRange)
{
currentState = State.Chase;
}
else
{
AttackPlayer();
}
break;
}
}
void ChasePlayer()
{
Vector2 direction = (player.position - transform.position).normalized;
transform.position = Vector2.MoveTowards(
transform.position,
player.position,
moveSpeed * Time.deltaTime
);
}
void AttackPlayer()
{
// ๊ณต๊ฒฉ ๋ก์ง
Debug.Log("ํ๋ ์ด์ด ๊ณต๊ฒฉ!");
}
}
๐๏ธ ๋์์ธ ํจํด๊ณผ ์ํคํ ์ฒ
์ฝ๋๋ฅผ ์ ์ง๋ ๊ฒ๋งํผ ์ค์ํ ๊ฒ **์ฝ๋๋ฅผ ์ ์ค๊ณํ๋ ๊ฒ**์ด์ผ. ๋์์ธ ํจํด์ ๋ฐ๋ณต๋๋ ๋ฌธ์ ์ ๋ํ ๊ฒ์ฆ๋ ํด๊ฒฐ์ฑ ์ด์ง.
์ฑ๊ธํค ํจํด
ํด๋์ค์ ์ธ์คํด์ค๊ฐ ํ๋๋ง ์กด์ฌํ๋๋ก ๋ณด์ฅ
public class GameManager
{
private static GameManager _instance;
public static GameManager Instance
{
get
{
if (_instance == null)
{
_instance = new GameManager();
}
return _instance;
}
}
private GameManager() { }
}
ํฉํ ๋ฆฌ ํจํด
๊ฐ์ฒด ์์ฑ ๋ก์ง์ ์บก์ํ
public interface IEnemy
{
void Attack();
}
public class EnemyFactory
{
public IEnemy CreateEnemy(string type)
{
return type switch
{
"Zombie" => new Zombie(),
"Skeleton" => new Skeleton(),
_ => throw new ArgumentException()
};
}
}
์ต์ ๋ฒ ํจํด
์ด๋ฒคํธ ๊ธฐ๋ฐ ํต์ (C# ์ด๋ฒคํธ๋ก ๊ตฌํ)
public class Player
{
public event Action<int> OnHealthChanged;
private int health;
public int Health
{
get => health;
set
{
health = value;
OnHealthChanged?.Invoke(health);
}
}
}
์ ๋ต ํจํด
์๊ณ ๋ฆฌ์ฆ์ ์บก์ํํ๊ณ ๊ต์ฒด ๊ฐ๋ฅํ๊ฒ
public interface IAttackStrategy
{
void Attack();
}
public class Character
{
private IAttackStrategy _attackStrategy;
public void SetAttackStrategy(IAttackStrategy strategy)
{
_attackStrategy = strategy;
}
public void PerformAttack()
{
_attackStrategy?.Attack();
}
}
๐๏ธ ํด๋ฆฐ ์ํคํ ์ฒ ์์น
SOLID ์์น:
โข Single Responsibility: ํ ํด๋์ค๋ ํ๋์ ์ฑ
์๋ง
โข Open/Closed: ํ์ฅ์๋ ์ด๋ ค์๊ณ ์์ ์๋ ๋ซํ์๊ฒ
โข Liskov Substitution: ์์ ํด๋์ค๋ ๋ถ๋ชจ ํด๋์ค๋ฅผ ๋์ฒด ๊ฐ๋ฅ
โข Interface Segregation: ์ธํฐํ์ด์ค๋ฅผ ์๊ฒ ๋ถ๋ฆฌ
โข Dependency Inversion: ๊ตฌ์ฒด์ ์ธ ๊ฒ์ด ์๋ ์ถ์์ ์์กด
// SOLID ์์น ์ ์ฉ ์์
// 1. Single Responsibility
// ๋์ ์: ํ ํด๋์ค๊ฐ ๋๋ฌด ๋ง์ ์ผ์ ํจ
public class User
{
public void SaveToDatabase() { }
public void SendEmail() { }
public void GenerateReport() { }
}
// ์ข์ ์: ์ฑ
์์ ๋ถ๋ฆฌ
public class User
{
public string Name { get; set; }
public string Email { get; set; }
}
public class UserRepository
{
public void Save(User user) { }
}
public class EmailService
{
public void SendEmail(User user) { }
}
// 2. Dependency Inversion
// ๋์ ์: ๊ตฌ์ฒด์ ์ธ ํด๋์ค์ ์์กด
public class OrderService
{
private SqlDatabase database = new SqlDatabase();
public void SaveOrder(Order order)
{
database.Save(order);
}
}
// ์ข์ ์: ์ธํฐํ์ด์ค์ ์์กด
public interface IDatabase
{
void Save(Order order);
}
public class OrderService
{
private readonly IDatabase _database;
public OrderService(IDatabase database)
{
_database = database;
}
public void SaveOrder(Order order)
{
_database.Save(order);
}
}
// ์ด์ ๋ค์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌํ์ฒด๋ฅผ ์ฌ์ฉ ๊ฐ๋ฅ
public class SqlDatabase : IDatabase
{
public void Save(Order order) { /* SQL ์ ์ฅ */ }
}
public class MongoDatabase : IDatabase
{
public void Save(Order order) { /* MongoDB ์ ์ฅ */ }
}
๐งช ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ (TDD)
์ข์ ๊ฐ๋ฐ์๋ ํ ์คํธ๋ฅผ ์์ฑํด. ๋ฒ๊ทธ๋ฅผ ๋ฏธ๋ฆฌ ์ก๊ณ , ๋ฆฌํฉํ ๋ง์ ์์ ํ๊ฒ ํ ์ ์๊ฑฐ๋ . C#์์๋ ์ฃผ๋ก xUnit, NUnit, MSTest๋ฅผ ์ฌ์ฉํด.
๋จ์ ํ ์คํธ ์์ฑํ๊ธฐ
xUnit์ ์ฌ์ฉํ ๊ธฐ๋ณธ์ ์ธ ํ ์คํธ ์์ ๋ฅผ ๋ณด์.
// ํ
์คํธํ ํด๋์ค
public class Calculator
{
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
public int Divide(int a, int b)
{
if (b == 0)
throw new DivideByZeroException();
return a / b;
}
}
// ํ
์คํธ ํด๋์ค
public class CalculatorTests
{
private readonly Calculator _calculator;
public CalculatorTests()
{
_calculator = new Calculator();
}
[Fact]
public void Add_TwoNumbers_ReturnsSum()
{
// Arrange (์ค๋น)
int a = 5;
int b = 3;
// Act (์คํ)
int result = _calculator.Add(a, b);
// Assert (๊ฒ์ฆ)
Assert.Equal(8, result);
}
[Theory]
[InlineData(10, 5, 5)]
[InlineData(20, 8, 12)]
[InlineData(0, 5, -5)]
public void Subtract_VariousNumbers_ReturnsCorrectResult(int a, int b, int expected)
{
// Act
int result = _calculator.Subtract(a, b);
// Assert
Assert.Equal(expected, result);
}
[Fact]
public void Divide_ByZero_ThrowsException()
{
// Arrange
int a = 10;
int b = 0;
// Act & Assert
Assert.Throws<DivideByZeroException>(() => _calculator.Divide(a, b));
}
}
// ๋ชจํน์ ์ฌ์ฉํ ํ
์คํธ (Moq ๋ผ์ด๋ธ๋ฌ๋ฆฌ)
public interface IUserRepository
{
User GetById(int id);
void Save(User user);
}
public class UserService
{
private readonly IUserRepository _repository;
public UserService(IUserRepository repository)
{
_repository = repository;
}
public bool UpdateUserEmail(int userId, string newEmail)
{
var user = _repository.GetById(userId);
if (user == null)
return false;
user.Email = newEmail;
_repository.Save(user);
return true;
}
}
// ํ
์คํธ
public class UserServiceTests
{
[Fact]
public void UpdateUserEmail_ValidUser_ReturnsTrue()
{
// Arrange
var mockRepo = new Mock<IUserRepository>();
var user = new User { Id = 1, Email = "old@email.com" };
mockRepo.Setup(r => r.GetById(1)).Returns(user);
mockRepo.Setup(r => r.Save(It.IsAny<User>())).Verifiable();
var service = new UserService(mockRepo.Object);
// Act
bool result = service.UpdateUserEmail(1, "new@email.com");
// Assert
Assert.True(result);
Assert.Equal("new@email.com", user.Email);
mockRepo.Verify(r => r.Save(user), Times.Once);
}
}
๐ 3๋จ๊ณ ํ์ต ์ ๋ต
๐ ์ค์ ํ๋ก์ ํธ ์ถ์ฒ
1. ๋ธ๋ก๊ทธ ํ๋ซํผ
ASP.NET Core MVC + EF Core + SQL Server
๊ธฐ๋ฅ: ํ์๊ฐ์
/๋ก๊ทธ์ธ, ๊ธ ์์ฑ/์์ /์ญ์ , ๋๊ธ, ๊ฒ์
2. RESTful API ์๋ฒ
ASP.NET Core Web API + JWT ์ธ์ฆ
๊ธฐ๋ฅ: ์ฌ์ฉ์ ์ธ์ฆ, CRUD ์์
, ํ์ด์ง, ํํฐ๋ง
3. ์ค์๊ฐ ์ฑํ
์ฑ
SignalR + ASP.NET Core
๊ธฐ๋ฅ: ์ค์๊ฐ ๋ฉ์์ง, ์ฑํ
๋ฐฉ, ์จ๋ผ์ธ ์ํ
4. 2D ํ๋ซํฌ๋จธ ๊ฒ์
Unity + C#
๊ธฐ๋ฅ: ํ๋ ์ด์ด ์ด๋, ์ AI, ์์ดํ
์์ง, ์ ์ ์์คํ
5. ์์
๊ด๋ฆฌ ์์คํ
Blazor + EF Core
๊ธฐ๋ฅ: ํ๋ก์ ํธ ๊ด๋ฆฌ, ํ์คํฌ ํ ๋น, ์งํ ์ํฉ ์ถ์
๐ 4๋จ๊ณ: ์ ๋ฌธ๊ฐ๋ก ์ฑ์ฅ (12๊ฐ์ ์ด์)
์ถํํด! ์ฌ๊ธฐ๊น์ง ์๋ค๋ฉด ์ด๋ฏธ ์ค๋ ฅ ์๋ ๊ฐ๋ฐ์์ผ. ์ด์ ๋ **๋ ๊น์ด ์๋ ์ง์๊ณผ ๋ฆฌ๋์ญ**์ ํค์ธ ์ฐจ๋ก์ผ.
โ๏ธ ํด๋ผ์ฐ๋์ ๋ง์ดํฌ๋ก์๋น์ค
ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ถ๋ถ ํด๋ผ์ฐ๋์์ ์คํ๋ผ. ํนํ C#์ Microsoft Azure์ ๊ถํฉ์ด ์ ๋ง ์ข์.
Azure ์๋น์ค
โข App Service: ์น ์ฑ ํธ์คํ
โข Functions: ์๋ฒ๋ฆฌ์ค ์ปดํจํ
โข SQL Database: ๊ด๋ฆฌํ ๋ฐ์ดํฐ๋ฒ ์ด์ค
โข Blob Storage: ํ์ผ ์ ์ฅ์
โข Service Bus: ๋ฉ์์ง
๋ง์ดํฌ๋ก์๋น์ค
โข ์๋น์ค ๋ถ๋ฆฌ ๋ฐ ๋
๋ฆฝ ๋ฐฐํฌ
โข API Gateway ํจํด
โข ์๋น์ค ๊ฐ ํต์ (gRPC, REST)
โข ๋ถ์ฐ ํธ๋์ญ์
โข ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ
// Azure Functions ์์
public static class HttpTriggerFunction
{
[FunctionName("ProcessOrder")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
HttpRequest req,
[Queue("orders")] IAsyncCollector<Order> orderQueue,
ILogger log)
{
log.LogInformation("์ฃผ๋ฌธ ์ฒ๋ฆฌ ์์");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var order = JsonSerializer.Deserialize<Order>(requestBody);
// ์ ํจ์ฑ ๊ฒ์ฌ
if (order == null || string.IsNullOrEmpty(order.ProductId))
{
return new BadRequestObjectResult("์๋ชป๋ ์ฃผ๋ฌธ ๋ฐ์ดํฐ");
}
// ํ์ ์ถ๊ฐ (๋น๋๊ธฐ ์ฒ๋ฆฌ)
await orderQueue.AddAsync(order);
return new OkObjectResult(new { message = "์ฃผ๋ฌธ์ด ์ ์๋์์ต๋๋ค", orderId = order.Id });
}
}
// ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ ํต์ (gRPC)
// Proto ํ์ผ ์ ์
/*
syntax = "proto3";
service ProductService {
rpc GetProduct (ProductRequest) returns (ProductResponse);
}
message ProductRequest {
string product_id = 1;
}
message ProductResponse {
string product_id = 1;
string name = 2;
double price = 3;
}
*/
// gRPC ์๋ฒ ๊ตฌํ
public class ProductService : ProductServiceBase
{
public override async Task<ProductResponse> GetProduct(
ProductRequest request,
ServerCallContext context)
{
// ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ ํ ์กฐํ
var product = await _repository.GetByIdAsync(request.ProductId);
return new ProductResponse
{
ProductId = product.Id,
Name = product.Name,
Price = product.Price
};
}
}
// gRPC ํด๋ผ์ด์ธํธ ์ฌ์ฉ
public class OrderService
{
private readonly ProductService.ProductServiceClient _productClient;
public async Task<Order> CreateOrderAsync(string productId, int quantity)
{
// ๋ค๋ฅธ ๋ง์ดํฌ๋ก์๋น์ค ํธ์ถ
var product = await _productClient.GetProductAsync(
new ProductRequest { ProductId = productId }
);
var order = new Order
{
ProductId = productId,
ProductName = product.Name,
Quantity = quantity,
TotalPrice = product.Price * quantity
};
return order;
}
}
๐ ๋ณด์๊ณผ ์ธ์ฆ
๋ณด์์ ์ ๋ ์ํํ ํด์๋ ์ ๋ผ. ํนํ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ๋์ฑ ์ค์ํด.
JWT ์ธ์ฆ ๊ตฌํ
JWT(JSON Web Token)๋ ํ๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ์ธ์ฆ ๋ฐฉ์์ด์ผ.
// JWT ํ ํฐ ์์ฑ
public class JwtTokenService
{
private readonly IConfiguration _configuration;
public JwtTokenService(IConfiguration configuration)
{
_configuration = configuration;
}
public string GenerateToken(User user)
{
var securityKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_configuration["Jwt:Key"])
);
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Email, user.Email),
new Claim(ClaimTypes.Role, user.Role)
};
var token = new JwtSecurityToken(
issuer: _configuration["Jwt:Issuer"],
audience: _configuration["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddHours(24),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public ClaimsPrincipal ValidateToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]);
try
{
var principal = tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = true,
ValidIssuer = _configuration["Jwt:Issuer"],
ValidateAudience = true,
ValidAudience = _configuration["Jwt:Audience"],
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
}, out SecurityToken validatedToken);
return principal;
}
catch
{
return null;
}
}
}
// ์ธ์ฆ ์ปจํธ๋กค๋ฌ
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly IUserService _userService;
private readonly JwtTokenService _tokenService;
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginRequest request)
{
// ์ฌ์ฉ์ ์ธ์ฆ
var user = await _userService.AuthenticateAsync(request.Username, request.Password);
if (user == null)
{
return Unauthorized(new { message = "์๋ชป๋ ์ฌ์ฉ์๋ช
๋๋ ๋น๋ฐ๋ฒํธ" });
}
// JWT ํ ํฐ ์์ฑ
var token = _tokenService.GenerateToken(user);
return Ok(new
{
token,
user = new
{
user.Id,
user.Username,
user.Email
}
});
}
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterRequest request)
{
// ๋น๋ฐ๋ฒํธ ํด์ฑ (์ ๋ ํ๋ฌธ์ผ๋ก ์ ์ฅํ์ง ๋ง ๊ฒ!)
var hashedPassword = BCrypt.Net.BCrypt.HashPassword(request.Password);
var user = new User
{
Username = request.Username,
Email = request.Email,
PasswordHash = hashedPassword,
Role = "User"
};
await _userService.CreateAsync(user);
return Ok(new { message = "ํ์๊ฐ์
์ฑ๊ณต" });
}
[Authorize] // JWT ์ธ์ฆ ํ์
[HttpGet("profile")]
public async Task<IActionResult> GetProfile()
{
// ํ์ฌ ์ธ์ฆ๋ ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
var userId = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier)?.Value);
var user = await _userService.GetByIdAsync(userId);
return Ok(user);
}
}
- โ ๏ธ ๋ณด์ ์ฒดํฌ๋ฆฌ์คํธ:
- โ ๋น๋ฐ๋ฒํธ๋ ํญ์ ํด์ฑํด์ ์ ์ฅ (BCrypt, Argon2)
- โ SQL Injection ๋ฐฉ์ง (ํ๋ผ๋ฏธํฐํ๋ ์ฟผ๋ฆฌ ์ฌ์ฉ)
- โ XSS ๊ณต๊ฒฉ ๋ฐฉ์ง (์ ๋ ฅ ๊ฒ์ฆ ๋ฐ ์ด์ค์ผ์ดํ)
- โ CSRF ํ ํฐ ์ฌ์ฉ
- โ HTTPS ์ฌ์ฉ (๋ฏผ๊ฐํ ๋ฐ์ดํฐ ์ ์ก)
- โ ์ ์ ํ ๊ถํ ๊ด๋ฆฌ (Role-based Access Control)
- โ ๋ก๊น ๋ฐ ๋ชจ๋ํฐ๋ง
โ๏ธ ์ฑ๋ฅ ์ต์ ํ
์ฝ๋๊ฐ ๋์ํ๋ ๊ฒ๋ ์ค์ํ์ง๋ง, **๋น ๋ฅด๊ฒ ๋์ํ๋ ๊ฒ**๋ ์ค์ํด. ํนํ ๋์ฉ๋ ํธ๋ํฝ์ ์ฒ๋ฆฌํด์ผ ํ ๋๋ ๋์ฑ ๊ทธ๋.
1๏ธโฃ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ต์ ํ
// ๋์ ์: N+1 ๋ฌธ์
public async Task<List<OrderDto>> GetOrdersAsync()
{
var orders = await _context.Orders.ToListAsync();
foreach (var order in orders)
{
// ๊ฐ ์ฃผ๋ฌธ๋ง๋ค ๋ณ๋์ ์ฟผ๋ฆฌ ์คํ! (N+1 ๋ฌธ์ )
order.Customer = await _context.Customers.FindAsync(order.CustomerId);
order.Items = await _context.OrderItems
.Where(i => i.OrderId == order.Id)
.ToListAsync();
}
return orders;
}
// ์ข์ ์: Eager Loading
public async Task<List<OrderDto>> GetOrdersAsync()
{
var orders = await _context.Orders
.Include(o => o.Customer) // ๊ด๋ จ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ๋ก๋
.Include(o => o.Items)
.ThenInclude(i => i.Product)
.ToListAsync();
return orders;
}
// ๋ ๋์ ์: ํ์ํ ๋ฐ์ดํฐ๋ง ์ ํ
public async Task<List<OrderDto>> GetOrdersAsync()
{
var orders = await _context.Orders
.Include(o => o.Customer)
.Include(o => o.Items)
.Select(o => new OrderDto
{
Id = o.Id,
OrderDate = o.OrderDate,
CustomerName = o.Customer.Name,
TotalAmount = o.Items.Sum(i => i.Price * i.Quantity),
ItemCount = o.Items.Count
})
.ToListAsync();
return orders;
}
2๏ธโฃ ์บ์ฑ ์ ๋ต
// ๋ฉ๋ชจ๋ฆฌ ์บ์ฑ
public class ProductService
{
private readonly IMemoryCache _cache;
private readonly IProductRepository _repository;
public async Task<Product> GetProductAsync(int id)
{
// ์บ์์์ ๋จผ์ ํ์ธ
if (_cache.TryGetValue($"product_{id}", out Product product))
{
return product;
}
// ์บ์์ ์์ผ๋ฉด DB์์ ์กฐํ
product = await _repository.GetByIdAsync(id);
// ์บ์์ ์ ์ฅ (10๋ถ ๋์ ์ ํจ)
var cacheOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromMinutes(10));
_cache.Set($"product_{id}", product, cacheOptions);
return product;
}
}
// Redis ๋ถ์ฐ ์บ์ฑ
public class DistributedCacheService
{
private readonly IDistributedCache _cache;
public async Task<T> GetOrCreateAsync<T>(
string key,
Func<Task<T>> factory,
TimeSpan? expiration = null)
{
// ์บ์์์ ์กฐํ
var cached = await _cache.GetStringAsync(key);
if (!string.IsNullOrEmpty(cached))
{
return JsonSerializer.Deserialize<T>(cached);
}
// ์บ์ ๋ฏธ์ค: ๋ฐ์ดํฐ ์์ฑ
var data = await factory();
// ์บ์์ ์ ์ฅ
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = expiration ?? TimeSpan.FromMinutes(30)
};
await _cache.SetStringAsync(
key,
JsonSerializer.Serialize(data),
options
);
return data;
}
}
3๏ธโฃ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๋ณ๋ ฌํ
// ์์ฐจ ์ฒ๋ฆฌ (๋๋ฆผ)
public async Task<List<Report>> GenerateReportsAsync(List<int> userIds)
{
var reports = new List<Report>();
foreach (var userId in userIds)
{
var report = await GenerateUserReportAsync(userId); // ํ๋์ฉ ์ฒ๋ฆฌ
reports.Add(report);
}
return reports;
}
// ๋ณ๋ ฌ ์ฒ๋ฆฌ (๋น ๋ฆ)
public async Task<List<Report>> GenerateReportsAsync(List<int> userIds)
{
var tasks = userIds.Select(userId => GenerateUserReportAsync(userId));
var reports = await Task.WhenAll(tasks); // ๋์์ ์ฒ๋ฆฌ
return reports.ToList();
}
// ๋ณ๋ ฌ ์ฒ๋ฆฌ + ์ ํ (๋ฆฌ์์ค ๋ณดํธ)
public async Task<List<Report>> GenerateReportsAsync(List<int> userIds)
{
var semaphore = new SemaphoreSlim(5); // ์ต๋ 5๊ฐ๊น์ง๋ง ๋์ ์คํ
var reports = new List<Report>();
var tasks = userIds.Select(async userId =>
{
await semaphore.WaitAsync();
try
{
return await GenerateUserReportAsync(userId);
}
finally
{
semaphore.Release();
}
});
return (await Task.WhenAll(tasks)).ToList();
}
๐ ๋ชจ๋ํฐ๋ง๊ณผ ๋ก๊น
ํ๋ก๋์ ํ๊ฒฝ์์๋ ๋ฌด์จ ์ผ์ด ์ผ์ด๋๋์ง ์์์ผ ํด. ๋ก๊น ๊ณผ ๋ชจ๋ํฐ๋ง์ ํ์์ผ!
// Serilog๋ฅผ ์ฌ์ฉํ ๊ตฌ์กฐํ๋ ๋ก๊น
public class OrderService
{
private readonly ILogger<OrderService> _logger;
public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
{
_logger.LogInformation(
"์ฃผ๋ฌธ ์์ฑ ์์: {@Request}",
request
);
try
{
var order = new Order
{
CustomerId = request.CustomerId,
Items = request.Items,
CreatedAt = DateTime.UtcNow
};
await _repository.AddAsync(order);
_logger.LogInformation(
"์ฃผ๋ฌธ ์์ฑ ์๋ฃ: OrderId={OrderId}, CustomerId={CustomerId}, Amount={Amount}",
order.Id,
order.CustomerId,
order.TotalAmount
);
return order;
}
catch (Exception ex)
{
_logger.LogError(
ex,
"์ฃผ๋ฌธ ์์ฑ ์คํจ: CustomerId={CustomerId}",
request.CustomerId
);
throw;
}
}
}
// Application Insights๋ฅผ ์ฌ์ฉํ ๋ชจ๋ํฐ๋ง
public class PerformanceMonitoringMiddleware
{
private readonly RequestDelegate _next;
private readonly TelemetryClient _telemetry;
public async Task InvokeAsync(HttpContext context)
{
var sw = Stopwatch.StartNew();
try
{
await _next(context);
}
finally
{
sw.Stop();
// ์ฑ๋ฅ ๋ฉํธ๋ฆญ ๊ธฐ๋ก
_telemetry.TrackMetric(
"RequestDuration",
sw.ElapsedMilliseconds,
new Dictionary<string, string>
{
{ "Path", context.Request.Path },
{ "Method", context.Request.Method },
{ "StatusCode", context.Response.StatusCode.ToString() }
}
);
// ๋๋ฆฐ ์์ฒญ ๊ฒฝ๊ณ
if (sw.ElapsedMilliseconds > 1000)
{
_telemetry.TrackTrace(
$"๋๋ฆฐ ์์ฒญ ๊ฐ์ง: {context.Request.Path} ({sw.ElapsedMilliseconds}ms)",
SeverityLevel.Warning
);
}
}
}
}
๐ฏ ํ์ต ๋ก๋๋งต ์ด์ ๋ฆฌ
๐ ๋จ๊ณ๋ณ ํ์ต ๊ธฐ๊ฐ (์ฐธ๊ณ ์ฉ)
1๋จ๊ณ (๊ธฐ์ด): 2-3๊ฐ์
โข ํ๋ฃจ 2-3์๊ฐ ํ์ต
โข ๋งค์ผ ์ฝ๋ฉ ์ฐ์ต
โข ์์ ํ๋ก์ ํธ 3-5๊ฐ
2๋จ๊ณ (์ค๊ธ): 3-4๊ฐ์
โข ํ๋ฃจ 3-4์๊ฐ ํ์ต
โข ์ค๊ฐ ๊ท๋ชจ ํ๋ก์ ํธ 2-3๊ฐ
โข ์คํ์์ค ๊ธฐ์ฌ ์์
3๋จ๊ณ (์ค์ ): 6-8๊ฐ์
โข ์ค์ ํ๋ก์ ํธ ๊ฒฝํ
โข ํ ํ์
๊ฒฝํ
โข ํฌํธํด๋ฆฌ์ค ๊ตฌ์ถ
4๋จ๊ณ (์ ๋ฌธ๊ฐ): ์ง์์ ํ์ต
โข ์๋ก์ด ๊ธฐ์ ์ต๋
โข ์ํคํ
์ฒ ์ค๊ณ ๊ฒฝํ
โข ๋ฉํ ๋ง ๋ฐ ์ง์ ๊ณต์
๐ก ์ฑ๊ณต์ ์ธ ํ์ต์ ์ํ ํ
๐ฏ ๋ชฉํ ์ค์
๋ง์ฐํ๊ฒ "C#์ ๋ฐฐ์ฐ๊ฒ ๋ค"๊ฐ ์๋๋ผ, "3๊ฐ์ ์์ ๊ฐ๋จํ ์น API๋ฅผ ๋ง๋ค๊ฒ ๋ค" ๊ฐ์ ๊ตฌ์ฒด์ ์ธ ๋ชฉํ๋ฅผ ์ธ์.
๐ ๋งค์ผ ์ฝ๋ฉ
ํ๋ฃจ 30๋ถ์ด๋ผ๋ ์ข์ผ๋ ๋งค์ผ ์ฝ๋๋ฅผ ์์ฑํด. ์ผ์ฃผ์ผ์ ํ ๋ฒ 5์๊ฐ ํ๋ ๊ฒ๋ณด๋ค ๋งค์ผ 30๋ถ์ด ํจ์ฌ ํจ๊ณผ์ ์ด์ผ.
๐ค ์ปค๋ฎค๋ํฐ ์ฐธ์ฌ
ํผ์ ๊ณต๋ถํ๋ฉด ํ๋ค์ด. ์จ๋ผ์ธ ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํ๊ณ , ์ง๋ฌธํ๊ณ , ๋ค๋ฅธ ์ฌ๋์ ๋์์ฃผ๋ฉด์ ํจ๊ป ์ฑ์ฅํ์.
๐ ์ฝ๋ ๋ฆฌ๋ทฐ
๋ค๋ฅธ ์ฌ๋์ ์ฝ๋๋ฅผ ์ฝ๊ณ , ๋ด ์ฝ๋๋ฅผ ๋ฆฌ๋ทฐ๋ฐ์. GitHub์์ ์คํ์์ค ํ๋ก์ ํธ๋ฅผ ๋ณด๋ ๊ฒ๋ ํฐ ๋์์ด ๋ผ.
๐ ๋ฌธ์ ์ฝ๊ธฐ
๊ณต์ ๋ฌธ์๋ฅผ ์ฝ๋ ์ต๊ด์ ๋ค์ฌ. Microsoft Docs๋ ์ ๋ง ์ ๋์ด ์์ด. ์์ด๊ฐ ๋ถ๋ด์ค๋ฝ๋ค๋ฉด ํ๊ธ ๋ฒ์ญ๋ ์์ด!
๐ ๋ฉํ ์ฐพ๊ธฐ
๊ฒฝํ ๋ง์ ๊ฐ๋ฐ์์๊ฒ ์กฐ์ธ์ ๊ตฌํด. ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ๋ฉํ ๋ฅผ ์ฐพ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ.
โ ๏ธ ํผํด์ผ ํ ์ค์๋ค
1. ํํ ๋ฆฌ์ผ ์ง์ฅ ๊ฐ์๋ง ๊ณ์ ๋ฃ๊ณ ์ค์ ๋ก ์ฝ๋ฉ์ ์ ํ๋ ๊ฑฐ. ๋ฐฐ์ด ๊ฑด ๋ฐ๋ก๋ฐ๋ก ์ง์ ๊ตฌํํด๋ด์ผ ํด!
2. ์๋ฒฝ์ฃผ์ ์ฒ์๋ถํฐ ์๋ฒฝํ ์ฝ๋๋ฅผ ์ฐ๋ ค๊ณ ํ์ง ๋ง. ์ผ๋จ ๋์ํ๊ฒ ๋ง๋ค๊ณ , ๊ทธ ๋ค์์ ๊ฐ์ ํด.
3. ๋๋ฌด ๋นจ๋ฆฌ ๋์ด๊ฐ๊ธฐ ๊ธฐ์ด๋ฅผ ๋์ถฉ ํ๊ณ ๊ณ ๊ธ ๋ด์ฉ์ผ๋ก ๋์ด๊ฐ๋ฉด ๋์ค์ ๋ฐ๋์ ๋งํ. ๊ธฐ์ด๋ฅผ ํํํ!
4. ํผ์๋ง ๊ณต๋ถํ๊ธฐ ๊ฐ๋ฐ์ ํ์ ์ด์ผ. ๋ค๋ฅธ ์ฌ๋๋ค๊ณผ ์ํตํ๊ณ , ์ฝ๋๋ฅผ ๊ณต์ ํ๊ณ , ํผ๋๋ฐฑ์ ์ฃผ๊ณ ๋ฐ์.
๐ ์ถ์ฒ ํ์ต ๋ฆฌ์์ค
๐ ๊ณต์ ๋ฌธ์ ๋ฐ ํํ ๋ฆฌ์ผ
โข Microsoft Learn - C# ๊ณต์ ํ์ต ๊ฒฝ๋ก
โข C# ํ๋ก๊ทธ๋๋ฐ ๊ฐ์ด๋ (docs.microsoft.com)
โข .NET API ๋ธ๋ผ์ฐ์
โข ASP.NET Core ๋ฌธ์
๐ ์ถ์ฒ ๋์
โข "C# 9.0 in a Nutshell" - Joseph Albahari
โข "ํด๋ฆฐ ์ฝ๋" - ๋ก๋ฒํธ C. ๋งํด
โข "์ดํํฐ๋ธ C#" - ๋น ์๊ทธ๋
โข "Head First Design Patterns" - ์๋ฆญ ํ๋ฆฌ๋จผ
๐ฅ ์จ๋ผ์ธ ๊ฐ์
โข Pluralsight - C# ์ ๋ฌธ ๊ฐ์
โข Udemy - ์
๋ฌธ๋ถํฐ ์ค์ ๊น์ง
โข YouTube - ์ฝ๋ฉ์ ํ, ๋๋ฆผ์ฝ๋ฉ
โข ์ธํ๋ฐ - ํ๊ธ ๊ฐ์
๐ป ์ค์ต ํ๋ซํผ
โข LeetCode - ์๊ณ ๋ฆฌ์ฆ ๋ฌธ์
โข ํ๋ก๊ทธ๋๋จธ์ค - ์ฝ๋ฉ ํ
์คํธ
โข Exercism - ๋ฉํ ๋ง ํฌํจ
โข HackerRank - ๋ค์ํ ๋ฌธ์
๐ค ์ปค๋ฎค๋ํฐ
โข Stack Overflow - ์ง๋ฌธ/๋ต๋ณ
โข Reddit r/csharp - ์์ด ์ปค๋ฎค๋ํฐ
โข OKKY - ํ๊ตญ ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ
โข ์ฌ๋ฅ๋ท - ๋ฉํ ๋ง ๋ฐ ์ง์ ๊ณต์
โข GitHub - ์คํ์์ค ํ๋ก์ ํธ
๐ ๋ง์น๋ฉฐ
์, ์ฌ๊ธฐ๊น์ง ์ฝ์๋ค๋ฉด ์ ๋ง ๋๋จํด! ๐ ์ด ๊ธด ๊ธ์ ๋๊น์ง ์ฝ์๋ค๋ ๊ฑด C# ๊ฐ๋ฐ์๊ฐ ๋๊ณ ์ถ์ ์ง์ฌ์ด ์๋ค๋ ๊ฑฐ์์?
์์งํ ๋งํ ๊ฒ. **๊ฐ๋ฐ์๊ฐ ๋๋ ๊ธธ์ ์ฝ์ง ์์.** ๋ฐฐ์์ผ ํ ๊ฒ๋ ๋ง๊ณ , ๋งํ๋ ๋ถ๋ถ๋ ๋ง์ ๊ฑฐ์ผ. ๋๋ก๋ "๋๋ ๊ฐ๋ฐ์ ์ฌ๋ฅ์ด ์๋?"๋ผ๋ ์๊ฐ์ด ๋ค ์๋ ์์ด. ํ์ง๋ง ๊ทธ๊ฑด ๋ชจ๋ ๊ฐ๋ฐ์๊ฐ ๊ฒช๋ ๊ณผ์ ์ด์ผ. ๋๋ ๊ทธ๋ฌ๊ณ , ์ง๊ธ ์๋์ด ๊ฐ๋ฐ์๋ค๋ ๋ค ๊ทธ๋ฌ์ด.
์ค์ํ ๊ฑด ํฌ๊ธฐํ์ง ์๋ ๊ฒ์ด์ผ. ๋งค์ผ ์กฐ๊ธ์ฉ์ด๋ผ๋ ์์ผ๋ก ๋์๊ฐ๋ฉด, ์ด๋์ "์ด? ๋ ์ด๊ฑฐ ํ ์ ์๋ค?"๋ผ๋ ์๊ฐ์ด ์. ๊ทธ ์๊ฐ์ ํฌ์ด์ ์ ๋ง ๋๋จํด. ๊ทธ๋ฆฌ๊ณ ๊ทธ๋ฐ ์๊ฐ๋ค์ด ์์ด๋ฉด์ ์ง์ง ๊ฐ๋ฐ์๊ฐ ๋๋ ๊ฑฐ์ง.
๐ฏ ๊ธฐ์ตํด์ผ ํ ๊ฒ๋ค
1. ๊ธฐ์ด๊ฐ ๊ฐ์ฅ ์ค์ํด. ํ๋ คํ ๊ธฐ์ ๋ณด๋ค ํํํ ๊ธฐ๋ณธ๊ธฐ๊ฐ ๋จผ์ ์ผ.
2. ๋งค์ผ ์ฝ๋ฉํ์. ํ๋ฃจ 30๋ถ์ด๋ผ๋ ์ข์ผ๋ ๊พธ์คํ ํ๋ ๊ฒ ํต์ฌ์ด์ผ.
3. ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ด. ์ด๋ก ๋ง ๊ณต๋ถํ์ง ๋ง๊ณ ์ค์ ๋ก ๋ญ๊ฐ๋ฅผ ๋ง๋ค์ด๋ณด์.
4. ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํด. ํผ์ ํ๋ฉด ํ๋ค์ด. ํจ๊ปํ๋ฉด ๋ ๋ฉ๋ฆฌ ๊ฐ ์ ์์ด.
5. ์ค์๋ฅผ ๋๋ ค์ํ์ง ๋ง. ์๋ฌ๋ ๋ฐฐ์์ ๊ธฐํ์ผ. ๋ง์ด ์ค์ํ๊ณ ๋ง์ด ๋ฐฐ์ฐ์.
6. ๋ฉํ ๋ฅผ ์ฐพ์๋ด. ๊ฒฝํ ๋ง์ ๊ฐ๋ฐ์์ ์กฐ์ธ์ ์ ๋ง ํฐ ๋์์ด ๋ผ. ์ฌ๋ฅ๋ท์์ ์ข์ ๋ฉํ ๋ฅผ ์ฐพ์๋ณด๋ ๊ฒ๋ ์ถ์ฒํด!
๋ง์ง๋ง์ผ๋ก ํ๊ณ ์ถ์ ๋ง์, **๋น์ ์ ํ ์ ์์ด!** ์ด ๊ธ์ ์ฝ๊ณ ์๋ค๋ ๊ฒ ์์ฒด๊ฐ ์ด๋ฏธ ์ข์ ์์์ด์ผ. ์ง๊ธ ๋น์ฅ Visual Studio๋ฅผ ์ผ๊ณ , ์ฒซ ๋ฒ์งธ "Hello, World!"๋ฅผ ์ถ๋ ฅํด๋ด. ๊ทธ๊ฒ ๋ฐ๋ก C# ๋ง์คํฐ๋ก ๊ฐ๋ ์ฒซ ๊ฑธ์์ด์ผ.
๊ฐ๋ฐ ๊ณต๋ถํ๋ค๊ฐ ๋งํ๊ฑฐ๋ ๊ถ๊ธํ ๊ฒ ์์ผ๋ฉด ์ธ์ ๋ ์ปค๋ฎค๋ํฐ์ ์ง๋ฌธํ๊ณ , ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๊ณผ ์ํตํด. ์ฐ๋ฆฌ ๋ชจ๋ ํจ๊ป ์ฑ์ฅํ๋ ๊ฑฐ์ผ. ํ์ดํ ! ๐ช
๐ ๋น์ ์ ๊ฐ๋ฐ์ ์ฌ์ ์ ์์ํฉ๋๋ค! ๐
์ง๋ฌธ์ด๋ ์กฐ์ธ์ด ํ์ํ๋ค๋ฉด ์ฌ๋ฅ๋ท์์ ๊ฒฝํ ๋ง์ ๋ฉํ ๋ค์ ๋ง๋๋ณด์ธ์.
ํจ๊ป ๋ฐฐ์ฐ๊ณ ์ฑ์ฅํ๋ ์ฆ๊ฑฐ์์ ๋๊ปด๋ณด์ธ์!
Happy Coding! ๐
C#๊ณผ ํจ๊ปํ๋ ๋ฉ์ง ๊ฐ๋ฐ์ ์ธ์์ ์์ํ์ธ์!
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.