์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐ŸŽญ C# ๋ฆฌํ”Œ๋ ‰์…˜๊ณผ ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ™œ์šฉ ๊ธฐ๋ฒ•

๐ŸŽญ C# ๋ฆฌํ”Œ๋ ‰์…˜๊ณผ ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ™œ์šฉ ๊ธฐ๋ฒ•

๋Ÿฐํƒ€์ž„์— ์ฝ”๋“œ๋ฅผ ๋“ค์—ฌ๋‹ค๋ณด๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๋งˆ๋ฒ• ๊ฐ™์€ ๊ธฐ์ˆ ! ๐Ÿ”ฎโœจ

๐Ÿš€ ๋ฆฌํ”Œ๋ ‰์…˜, ์ด๊ฒŒ ๋ญ”๋ฐ ์ด๋ ‡๊ฒŒ ์‹ ๊ธฐํ•ด?

์นœ๊ตฌ์•ผ, ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ์ž๊ธฐ ์ž์‹ ์˜ ์ฝ”๋“œ๋ฅผ ๋“ค์—ฌ๋‹ค๋ณผ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์–ด๋–จ๊นŒ? ๐Ÿค”
๋งˆ์น˜ ๊ฑฐ์šธ์„ ๋ณด๋“ฏ์ด ์ž์‹ ์˜ ๊ตฌ์กฐ๋ฅผ ํŒŒ์•…ํ•˜๊ณ , ์‹ฌ์ง€์–ด ๊ทธ๊ฑธ ๋ฐ”๊ฟ€ ์ˆ˜๋„ ์žˆ๋‹ค๋ฉด?
๋ฐ”๋กœ ๊ทธ๊ฒŒ ๋ฆฌํ”Œ๋ ‰์…˜(Reflection)์ด์•ผ!

C#์—์„œ ๋ฆฌํ”Œ๋ ‰์…˜์€ ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰ ์ค‘์— ์ž์‹ ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ  ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ด์•ผ.
์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด, ์ฝ”๋“œ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ฝ๊ณ  ๋ถ„์„ํ•˜๋Š” ๊ฑฐ์ง€. ๐Ÿ˜Ž
์ปดํŒŒ์ผ ํƒ€์ž„์—๋Š” ๋ชฐ๋ž๋˜ ํƒ€์ž… ์ •๋ณด๋ฅผ ๋Ÿฐํƒ€์ž„์— ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๊ณ ,
์‹ฌ์ง€์–ด ๋™์ ์œผ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜๋„ ์žˆ์–ด!

๐Ÿ’ก ๋ฆฌํ”Œ๋ ‰์…˜์ด ํ•„์š”ํ•œ ์ˆœ๊ฐ„๋“ค:

โ€ข ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ ๊ตฌ์ถ•ํ•  ๋•Œ (์™ธ๋ถ€ DLL์„ ๋™์ ์œผ๋กœ ๋กœ๋“œ)
โ€ข ORM(Object-Relational Mapping) ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐœ๋ฐœ
โ€ข ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋งŒ๋“ค ๋•Œ
โ€ข ์˜์กด์„ฑ ์ฃผ์ž…(DI) ์ปจํ…Œ์ด๋„ˆ ๊ตฌํ˜„
โ€ข ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๋ชฉ(Mock) ๊ฐ์ฒด ์ƒ์„ฑ
โ€ข ๋Ÿฐํƒ€์ž„์— ํƒ€์ž… ์ •๋ณด๋ฅผ ์•Œ์•„์•ผ ํ•˜๋Š” ๋ชจ๋“  ์ƒํ™ฉ! ๐ŸŽฏ
๋ฆฌํ”Œ๋ ‰์…˜์˜ ๋™์ž‘ ์›๋ฆฌ ์ปดํŒŒ์ผ ํƒ€์ž„ ์†Œ์Šค ์ฝ”๋“œ โ†“ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ƒ์„ฑ ๋ณ€ํ™˜ ๋Ÿฐํƒ€์ž„ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ฝ๊ธฐ โ†“ ๋™์  ์‹คํ–‰ ๋ฆฌํ”Œ๋ ‰์…˜ ๊ฒฐ๊ณผ ํƒ€์ž… ์ •๋ณด ํš๋“ ๋™์  ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์กฐ์ž‘ Type Assembly Method Property ํ•ต์‹ฌ ๋ฆฌํ”Œ๋ ‰์…˜ ์š”์†Œ๋“ค

๐Ÿ” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋Š” "๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ"์•ผ. ๐ŸŽช
C#์—์„œ๋Š” ์–ด์…ˆ๋ธ”๋ฆฌ(Assembly)์— ํฌํ•จ๋œ ํƒ€์ž…, ๋ฉ”์„œ๋“œ, ํ”„๋กœํผํ‹ฐ, ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ๋งํ•ด.
์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผํ•  ๋•Œ ์ด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์„œ ์–ด์…ˆ๋ธ”๋ฆฌ์— ํ•จ๊ป˜ ์ €์žฅํ•˜์ง€.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋„ˆ๊ฐ€ class Person์ด๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋ฉด,
์ปดํŒŒ์ผ๋Ÿฌ๋Š” "Person์ด๋ผ๋Š” ํด๋ž˜์Šค๊ฐ€ ์žˆ๊ณ , ์ด ํด๋ž˜์Šค์—๋Š” Name์ด๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๊ณ ,
GetAge()๋ผ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋‹ค"๋Š” ์ •๋ณด๋ฅผ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋กœ ์ €์žฅํ•ด.
๋ฆฌํ”Œ๋ ‰์…˜์€ ๋ฐ”๋กœ ์ด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์„œ ํ™œ์šฉํ•˜๋Š” ๊ฑฐ์•ผ! ๐Ÿ“š

๐ŸŽฏ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์— ํฌํ•จ๋˜๋Š” ์ •๋ณด๋“ค:

โ€ข ํƒ€์ž… ์ด๋ฆ„๊ณผ ๋„ค์ž„์ŠคํŽ˜์ด์Šค
โ€ข ์ƒ์† ๊ด€๊ณ„ ๋ฐ ๊ตฌํ˜„๋œ ์ธํ„ฐํŽ˜์ด์Šค
โ€ข ๋ฉค๋ฒ„ ์ •๋ณด (ํ•„๋“œ, ํ”„๋กœํผํ‹ฐ, ๋ฉ”์„œ๋“œ, ์ด๋ฒคํŠธ)
โ€ข ์ ‘๊ทผ ์ œํ•œ์ž (public, private ๋“ฑ)
โ€ข ์ปค์Šคํ…€ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ
โ€ข ์ œ๋„ค๋ฆญ ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜
โ€ข ์–ด์…ˆ๋ธ”๋ฆฌ ๋ฒ„์ „ ๋ฐ ์ฐธ์กฐ ์ •๋ณด

โš™๏ธ System.Reflection ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํŒŒํ—ค์น˜๊ธฐ

C#์—์„œ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด System.Reflection ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์•Œ์•„์•ผ ํ•ด.
์—ฌ๊ธฐ์—๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ ์ž‘์—…์— ํ•„์š”ํ•œ ํ•ต์‹ฌ ํด๋ž˜์Šค๋“ค์ด ๋ชจ์—ฌ ์žˆ์–ด! ๐Ÿ› ๏ธ

ํด๋ž˜์Šค ์—ญํ•  ์ฃผ์š” ์šฉ๋„
Type ํƒ€์ž… ์ •๋ณด ํ‘œํ˜„ ํด๋ž˜์Šค, ์ธํ„ฐํŽ˜์ด์Šค, ๊ตฌ์กฐ์ฒด ๋“ฑ์˜ ํƒ€์ž… ์ •๋ณด ์กฐํšŒ
Assembly ์–ด์…ˆ๋ธ”๋ฆฌ ํ‘œํ˜„ DLL/EXE ๋กœ๋“œ, ํƒ€์ž… ๊ฒ€์ƒ‰
MethodInfo ๋ฉ”์„œ๋“œ ์ •๋ณด ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜, ๋™์  ํ˜ธ์ถœ
PropertyInfo ํ”„๋กœํผํ‹ฐ ์ •๋ณด ํ”„๋กœํผํ‹ฐ ๊ฐ’ ์ฝ๊ธฐ/์“ฐ๊ธฐ
FieldInfo ํ•„๋“œ ์ •๋ณด ํ•„๋“œ ๊ฐ’ ์ ‘๊ทผ ๋ฐ ์ˆ˜์ •
ConstructorInfo ์ƒ์„ฑ์ž ์ •๋ณด ๋™์  ๊ฐ์ฒด ์ƒ์„ฑ
EventInfo ์ด๋ฒคํŠธ ์ •๋ณด ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ถ”๊ฐ€/์ œ๊ฑฐ

๐Ÿ’ป ๊ธฐ๋ณธ ๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ๋ฒ• - Type ๊ฐ์ฒด ์–ป๊ธฐ

๋ฆฌํ”Œ๋ ‰์…˜์˜ ์‹œ์ž‘์€ Type ๊ฐ์ฒด๋ฅผ ์–ป๋Š” ๊ฒƒ๋ถ€ํ„ฐ์•ผ! ๐ŸŽฌ
Type ๊ฐ์ฒด๋ฅผ ์–ป๋Š” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€๊ฐ€ ์žˆ์–ด:

1๏ธโƒฃ typeof ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ (์ปดํŒŒ์ผ ํƒ€์ž„์— ํƒ€์ž…์„ ์•Œ ๋•Œ)

Type type1 = typeof(string);
Type type2 = typeof(List<int>);
Type type3 = typeof(MyCustomClass);

Console.WriteLine(type1.Name);  // String
Console.WriteLine(type1.FullName);  // System.String
Console.WriteLine(type1.Namespace);  // System

2๏ธโƒฃ GetType() ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ (๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ์„ ๋•Œ)

string text = "Hello, Reflection!";
Type type = text.GetType();

int number = 42;
Type numType = number.GetType();

Console.WriteLine(type.Name);  // String
Console.WriteLine(numType.Name);  // Int32

3๏ธโƒฃ Type.GetType() ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ (๋ฌธ์ž์—ด๋กœ ํƒ€์ž… ์ด๋ฆ„์„ ์•Œ ๋•Œ)

// ์ •๊ทœํ™”๋œ ํƒ€์ž… ์ด๋ฆ„ ์‚ฌ์šฉ
Type type1 = Type.GetType("System.String");
Type type2 = Type.GetType("System.Collections.Generic.List`1");

// ๊ฐ™์€ ์–ด์…ˆ๋ธ”๋ฆฌ ๋‚ด์˜ ํƒ€์ž…
Type type3 = Type.GetType("MyNamespace.MyClass");

if (type1 != null)
{
    Console.WriteLine($"ํƒ€์ž…์„ ์ฐพ์•˜์–ด์š”: {type1.FullName}");
}
โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ:
Type.GetType()์€ ํƒ€์ž…์„ ์ฐพ์ง€ ๋ชปํ•˜๋ฉด null์„ ๋ฐ˜ํ™˜ํ•ด.
๋‹ค๋ฅธ ์–ด์…ˆ๋ธ”๋ฆฌ์˜ ํƒ€์ž…์„ ์ฐพ์œผ๋ ค๋ฉด ์–ด์…ˆ๋ธ”๋ฆฌ ์ •๊ทœํ™”๋œ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ด!
์˜ˆ: "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

๐Ÿ”Ž ํƒ€์ž… ์ •๋ณด ํƒ์ƒ‰ํ•˜๊ธฐ

Type ๊ฐ์ฒด๋ฅผ ์–ป์—ˆ๋‹ค๋ฉด, ์ด์ œ ๊ทธ ํƒ€์ž…์— ๋Œ€ํ•œ ์˜จ๊ฐ– ์ •๋ณด๋ฅผ ์บ๋‚ผ ์ˆ˜ ์žˆ์–ด! ๐Ÿ•ต๏ธ
์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์ œ๋ฅผ ํ•œ๋ฒˆ ๋ณผ๊นŒ?

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    private string _secret = "๋น„๋ฐ€์ด์•ผ!";
    
    public Person() { }
    
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    
    public void SayHello()
    {
        Console.WriteLine($"์•ˆ๋…•! ๋‚˜๋Š” {Name}์ด์•ผ!");
    }
    
    private void SecretMethod()
    {
        Console.WriteLine("์ด๊ฑด ๋น„๋ฐ€ ๋ฉ”์„œ๋“œ!");
    }
}

// ๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ Person ํด๋ž˜์Šค ๋ถ„์„ํ•˜๊ธฐ
Type personType = typeof(Person);

Console.WriteLine($"๐Ÿ“Œ ํƒ€์ž… ์ด๋ฆ„: {personType.Name}");
Console.WriteLine($"๐Ÿ“Œ ์ „์ฒด ์ด๋ฆ„: {personType.FullName}");
Console.WriteLine($"๐Ÿ“Œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค: {personType.Namespace}");
Console.WriteLine($"๐Ÿ“Œ ํด๋ž˜์Šค์ธ๊ฐ€? {personType.IsClass}");
Console.WriteLine($"๐Ÿ“Œ ์ถ”์ƒ ํด๋ž˜์Šค์ธ๊ฐ€? {personType.IsAbstract}");
Console.WriteLine($"๐Ÿ“Œ ๋ด‰์ธ(sealed)๋˜์—ˆ๋‚˜? {personType.IsSealed}");

// ํ”„๋กœํผํ‹ฐ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
Console.WriteLine("\n๐Ÿ” ํ”„๋กœํผํ‹ฐ ๋ชฉ๋ก:");
PropertyInfo[] properties = personType.GetProperties();
foreach (var prop in properties)
{
    Console.WriteLine($"  - {prop.Name} ({prop.PropertyType.Name})");
    Console.WriteLine($"    ์ฝ๊ธฐ ๊ฐ€๋Šฅ: {prop.CanRead}, ์“ฐ๊ธฐ ๊ฐ€๋Šฅ: {prop.CanWrite}");
}

// ๋ฉ”์„œ๋“œ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
Console.WriteLine("\n๐Ÿ” ๋ฉ”์„œ๋“œ ๋ชฉ๋ก:");
MethodInfo[] methods = personType.GetMethods(
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (var method in methods)
{
    Console.WriteLine($"  - {method.Name}");
    Console.WriteLine($"    ๋ฐ˜ํ™˜ ํƒ€์ž…: {method.ReturnType.Name}");
    
    ParameterInfo[] parameters = method.GetParameters();
    if (parameters.Length > 0)
    {
        Console.WriteLine("    ๋งค๊ฐœ๋ณ€์ˆ˜:");
        foreach (var param in parameters)
        {
            Console.WriteLine($"      โ€ข {param.Name} ({param.ParameterType.Name})");
        }
    }
}

// ์ƒ์„ฑ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
Console.WriteLine("\n๐Ÿ” ์ƒ์„ฑ์ž ๋ชฉ๋ก:");
ConstructorInfo[] constructors = personType.GetConstructors();
foreach (var ctor in constructors)
{
    ParameterInfo[] parameters = ctor.GetParameters();
    Console.WriteLine($"  - ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐœ์ˆ˜: {parameters.Length}");
    foreach (var param in parameters)
    {
        Console.WriteLine($"    โ€ข {param.Name} ({param.ParameterType.Name})");
    }
}

์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด Person ํด๋ž˜์Šค์˜ ๋ชจ๋“  ๊ตฌ์กฐ๋ฅผ ๋Ÿฐํƒ€์ž„์— ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ˜ฒ
๋งˆ์น˜ X-ray๋กœ ํด๋ž˜์Šค ๋‚ด๋ถ€๋ฅผ ๋“ค์—ฌ๋‹ค๋ณด๋Š” ๊ฒƒ ๊ฐ™์ง€?

๐ŸŽฏ BindingFlags - ๊ฒ€์ƒ‰ ๋ฒ”์œ„ ์ง€์ •ํ•˜๊ธฐ

๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ๋ฉค๋ฒ„๋ฅผ ๊ฒ€์ƒ‰ํ•  ๋•Œ BindingFlags๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด
์–ด๋–ค ๋ฉค๋ฒ„๋ฅผ ์ฐพ์„์ง€ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽ›๏ธ

์ฃผ์š” BindingFlags ์˜ต์…˜:

์ ‘๊ทผ์„ฑ ๊ด€๋ จ:
โ€ข Public - public ๋ฉค๋ฒ„๋งŒ
โ€ข NonPublic - private, protected, internal ๋ฉค๋ฒ„

๋ฉค๋ฒ„ ์ข…๋ฅ˜:
โ€ข Instance - ์ธ์Šคํ„ด์Šค ๋ฉค๋ฒ„
โ€ข Static - ์ •์ (static) ๋ฉค๋ฒ„

์ƒ์† ๊ด€๋ จ:
โ€ข DeclaredOnly - ํ•ด๋‹น ํƒ€์ž…์—์„œ ์ง์ ‘ ์„ ์–ธ๋œ ๋ฉค๋ฒ„๋งŒ (์ƒ์†๋œ ๋ฉค๋ฒ„ ์ œ์™ธ)
โ€ข FlattenHierarchy - ์ƒ์† ๊ณ„์ธต ์ „์ฒด์—์„œ ์ •์  ๋ฉค๋ฒ„ ํฌํ•จ

๊ธฐํƒ€:
โ€ข IgnoreCase - ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„ ์•ˆ ํ•จ
โ€ข CreateInstance - ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ์‹œ ์‚ฌ์šฉ
Type type = typeof(Person);

// public ์ธ์Šคํ„ด์Šค ๋ฉค๋ฒ„๋งŒ
var publicMembers = type.GetMembers(BindingFlags.Public | BindingFlags.Instance);

// private ์ธ์Šคํ„ด์Šค ํ•„๋“œ๋งŒ
var privateFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);

// ๋ชจ๋“  ๋ฉ”์„œ๋“œ (public + private, instance + static)
var allMethods = type.GetMethods(
    BindingFlags.Public | BindingFlags.NonPublic | 
    BindingFlags.Instance | BindingFlags.Static);

// ํŠน์ • ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ ์ฐพ๊ธฐ (๋Œ€์†Œ๋ฌธ์ž ๋ฌด์‹œ)
var method = type.GetMethod("sayhello", 
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);

Console.WriteLine($"์ฐพ์€ ๋ฉ”์„œ๋“œ: {method?.Name}");

๐Ÿš€ ๋™์ ์œผ๋กœ ๊ฐ์ฒด ์ƒ์„ฑํ•˜๊ธฐ

๋ฆฌํ”Œ๋ ‰์…˜์˜ ์ง„์งœ ๋งค๋ ฅ์€ ๋Ÿฐํƒ€์ž„์— ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑฐ์•ผ! ๐ŸŽจ
์ปดํŒŒ์ผ ํƒ€์ž„์—๋Š” ์–ด๋–ค ํƒ€์ž…์ธ์ง€ ๋ชฐ๋ผ๋„, ์‹คํ–‰ ์ค‘์— ๋™์ ์œผ๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€.

๋ฐฉ๋ฒ• 1: Activator.CreateInstance ์‚ฌ์šฉ (๊ฐ€์žฅ ๊ฐ„๋‹จ)

// ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋กœ ๊ฐ์ฒด ์ƒ์„ฑ
Type type = typeof(Person);
object instance = Activator.CreateInstance(type);

// ์ œ๋„ค๋ฆญ ๋ฒ„์ „ (ํƒ€์ž… ์บ์ŠคํŒ… ๋ถˆํ•„์š”)
Person person = Activator.CreateInstance<Person>();

// ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” ์ƒ์„ฑ์ž ์‚ฌ์šฉ
object instance2 = Activator.CreateInstance(type, "ํ™๊ธธ๋™", 25);
Person person2 = (Person)instance2;

person2.SayHello();  // "์•ˆ๋…•! ๋‚˜๋Š” ํ™๊ธธ๋™์ด์•ผ!"

๋ฐฉ๋ฒ• 2: ConstructorInfo ์‚ฌ์šฉ (๋” ์„ธ๋ฐ€ํ•œ ์ œ์–ด)

Type type = typeof(Person);

// ํŠน์ • ์ƒ์„ฑ์ž ์ฐพ๊ธฐ
ConstructorInfo constructor = type.GetConstructor(
    new Type[] { typeof(string), typeof(int) });

if (constructor != null)
{
    // ์ƒ์„ฑ์ž ํ˜ธ์ถœ
    object instance = constructor.Invoke(new object[] { "์ด์ˆœ์‹ ", 30 });
    Person person = (Person)instance;
    
    person.SayHello();  // "์•ˆ๋…•! ๋‚˜๋Š” ์ด์ˆœ์‹ ์ด์•ผ!"
}

// ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ์ฐพ๊ธฐ
ConstructorInfo defaultCtor = type.GetConstructor(Type.EmptyTypes);
object instance2 = defaultCtor?.Invoke(null);

๋ฐฉ๋ฒ• 3: FormatterServices (๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ, ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ๋งŒ)

using System.Runtime.Serialization;

// ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ๊ฐ์ฒด ์ƒ์„ฑ (์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ์ƒํƒœ)
Type type = typeof(Person);
object instance = FormatterServices.GetUninitializedObject(type);

// ์ฃผ์˜: ์ƒ์„ฑ์ž๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํ•„๋“œ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์Œ!
// ์ง๋ ฌํ™” ํ”„๋ ˆ์ž„์›Œํฌ ๋“ฑ ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ
๐Ÿ’ก ์„ฑ๋Šฅ ํŒ:
๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ž์ฃผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค๋ฉด, Activator.CreateInstance๋ณด๋‹ค
Delegate๋‚˜ Expression Tree๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒŒ ํ›จ์”ฌ ๋นจ๋ผ!
ํ•œ ๋ฒˆ ๋งŒ๋“ค์–ด๋‘๋ฉด ์ผ๋ฐ˜ ์ƒ์„ฑ์ž ํ˜ธ์ถœ๊ณผ ๋น„์Šทํ•œ ์†๋„๋กœ ๋™์ž‘ํ•ด. ๐Ÿƒโ€โ™‚๏ธ

๐ŸŽช ๋™์ ์œผ๋กœ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœํ•˜๊ธฐ

๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์—ˆ์œผ๋‹ˆ ์ด์ œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด๋ณผ๊นŒ? ๐Ÿ˜Ž
๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ”์„œ๋“œ ์ด๋ฆ„๋งŒ ์•Œ๋ฉด ๋™์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์–ด!

Person person = new Person("๊น€์ฒ ์ˆ˜", 28);
Type type = person.GetType();

// ๋ฉ”์„œ๋“œ ์ฐพ๊ธฐ
MethodInfo method = type.GetMethod("SayHello");

if (method != null)
{
    // ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ (๋งค๊ฐœ๋ณ€์ˆ˜ ์—†์Œ)
    method.Invoke(person, null);
    // ์ถœ๋ ฅ: "์•ˆ๋…•! ๋‚˜๋Š” ๊น€์ฒ ์ˆ˜์•ผ!"
}

// ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์˜ˆ์ œ
public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }
    
    public double Multiply(double x, double y)
    {
        return x * y;
    }
}

Calculator calc = new Calculator();
Type calcType = calc.GetType();

// Add ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
MethodInfo addMethod = calcType.GetMethod("Add");
object result = addMethod.Invoke(calc, new object[] { 10, 20 });
Console.WriteLine($"10 + 20 = {result}");  // 30

// Multiply ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
MethodInfo multiplyMethod = calcType.GetMethod("Multiply");
object result2 = multiplyMethod.Invoke(calc, new object[] { 3.5, 2.0 });
Console.WriteLine($"3.5 ร— 2.0 = {result2}");  // 7.0

private ๋ฉ”์„œ๋“œ๋„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ”“

Type type = typeof(Person);
Person person = new Person("๋น„๋ฐ€์š”์›", 35);

// private ๋ฉ”์„œ๋“œ ์ฐพ๊ธฐ
MethodInfo secretMethod = type.GetMethod("SecretMethod", 
    BindingFlags.NonPublic | BindingFlags.Instance);

if (secretMethod != null)
{
    // private ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ!
    secretMethod.Invoke(person, null);
    // ์ถœ๋ ฅ: "์ด๊ฑด ๋น„๋ฐ€ ๋ฉ”์„œ๋“œ!"
}

// ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” private ๋ฉค๋ฒ„์—๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅ!
// ํ•˜์ง€๋งŒ ์บก์Аํ™”๋ฅผ ๊นจ๋œจ๋ฆฌ๋Š” ๊ฑฐ๋‹ˆ๊นŒ ์ •๋ง ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ด.

์ œ๋„ค๋ฆญ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœํ•˜๊ธฐ ๐ŸŽฏ

public class GenericClass
{
    public T CreateInstance<T>() where T : new()
    {
        return new T();
    }
    
    public List<T> CreateList<T>(params T[] items)
    {
        return new List<T>(items);
    }
}

GenericClass obj = new GenericClass();
Type type = obj.GetType();

// ์ œ๋„ค๋ฆญ ๋ฉ”์„œ๋“œ ์ฐพ๊ธฐ
MethodInfo method = type.GetMethod("CreateList");

// ํƒ€์ž… ์ธ์ž ์ง€์ • (MakeGenericMethod)
MethodInfo genericMethod = method.MakeGenericMethod(typeof(string));

// ํ˜ธ์ถœ
object result = genericMethod.Invoke(obj, new object[] { 
    new string[] { "์‚ฌ๊ณผ", "๋ฐ”๋‚˜๋‚˜", "์ฒด๋ฆฌ" } 
});

List<string> fruits = (List<string>)result;
Console.WriteLine($"๊ณผ์ผ ๊ฐœ์ˆ˜: {fruits.Count}");  // 3

๐Ÿ“ฆ ํ”„๋กœํผํ‹ฐ์™€ ํ•„๋“œ ๊ฐ’ ์ฝ๊ณ  ์“ฐ๊ธฐ

๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋‚˜ ํ•„๋“œ ๊ฐ’์„ ๋™์ ์œผ๋กœ ์ฝ๊ณ  ์“ธ ์ˆ˜ ์žˆ์–ด! ๐Ÿ“
์ด๊ฑด ํŠนํžˆ ์ง๋ ฌํ™”๋‚˜ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉํ•  ๋•Œ ์—„์ฒญ ์œ ์šฉํ•ด.

Person person = new Person("๋ฐ•์˜ํฌ", 32);
Type type = person.GetType();

// ํ”„๋กœํผํ‹ฐ ๊ฐ’ ์ฝ๊ธฐ
PropertyInfo nameProp = type.GetProperty("Name");
object nameValue = nameProp.GetValue(person);
Console.WriteLine($"์ด๋ฆ„: {nameValue}");  // "๋ฐ•์˜ํฌ"

PropertyInfo ageProp = type.GetProperty("Age");
object ageValue = ageProp.GetValue(person);
Console.WriteLine($"๋‚˜์ด: {ageValue}");  // 32

// ํ”„๋กœํผํ‹ฐ ๊ฐ’ ์“ฐ๊ธฐ
nameProp.SetValue(person, "์ตœ๋ฏผ์ˆ˜");
ageProp.SetValue(person, 40);

Console.WriteLine($"๋ณ€๊ฒฝ๋œ ์ด๋ฆ„: {person.Name}");  // "์ตœ๋ฏผ์ˆ˜"
Console.WriteLine($"๋ณ€๊ฒฝ๋œ ๋‚˜์ด: {person.Age}");  // 40

// ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ ์ˆœํšŒํ•˜๋ฉด์„œ ๊ฐ’ ์ถœ๋ ฅ
Console.WriteLine("\n๐Ÿ“‹ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ ๊ฐ’:");
foreach (PropertyInfo prop in type.GetProperties())
{
    object value = prop.GetValue(person);
    Console.WriteLine($"{prop.Name}: {value}");
}

private ํ•„๋“œ ์ ‘๊ทผํ•˜๊ธฐ ๐Ÿ•ต๏ธ

Type type = typeof(Person);
Person person = new Person("์ŠคํŒŒ์ด", 28);

// private ํ•„๋“œ ์ฐพ๊ธฐ
FieldInfo secretField = type.GetField("_secret", 
    BindingFlags.NonPublic | BindingFlags.Instance);

if (secretField != null)
{
    // private ํ•„๋“œ ๊ฐ’ ์ฝ๊ธฐ
    object secretValue = secretField.GetValue(person);
    Console.WriteLine($"๋น„๋ฐ€ ์ •๋ณด: {secretValue}");  // "๋น„๋ฐ€์ด์•ผ!"
    
    // private ํ•„๋“œ ๊ฐ’ ๋ณ€๊ฒฝ
    secretField.SetValue(person, "์ด์ œ ๋น„๋ฐ€์ด ์•„๋‹ˆ์•ผ!");
    
    object newValue = secretField.GetValue(person);
    Console.WriteLine($"๋ณ€๊ฒฝ๋œ ๋น„๋ฐ€: {newValue}");  // "์ด์ œ ๋น„๋ฐ€์ด ์•„๋‹ˆ์•ผ!"
}

์ธ๋ฑ์„œ ํ”„๋กœํผํ‹ฐ ๋‹ค๋ฃจ๊ธฐ ๐Ÿ“Š

public class DataCollection
{
    private Dictionary<string, object> _data = new Dictionary<string, object>();
    
    public object this[string key]
    {
        get { return _data.ContainsKey(key) ? _data[key] : null; }
        set { _data[key] = value; }
    }
}

DataCollection collection = new DataCollection();
Type type = collection.GetType();

// ์ธ๋ฑ์„œ ํ”„๋กœํผํ‹ฐ ์ฐพ๊ธฐ (์ด๋ฆ„์€ "Item")
PropertyInfo indexer = type.GetProperty("Item");

// ์ธ๋ฑ์„œ๋กœ ๊ฐ’ ์„ค์ •
indexer.SetValue(collection, "์•ˆ๋…•ํ•˜์„ธ์š”!", new object[] { "greeting" });

// ์ธ๋ฑ์„œ๋กœ ๊ฐ’ ์ฝ๊ธฐ
object value = indexer.GetValue(collection, new object[] { "greeting" });
Console.WriteLine(value);  // "์•ˆ๋…•ํ•˜์„ธ์š”!"

๐Ÿท๏ธ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ(Attribute) ํ™œ์šฉํ•˜๊ธฐ

์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋Š” ์ฝ”๋“œ์— ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด์•ผ! ๐ŸŽจ
๋ฆฌํ”Œ๋ ‰์…˜๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.
์˜ˆ๋ฅผ ๋“ค์–ด, ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ API ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜,
์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€! ๐Ÿ’ช

์ปค์Šคํ…€ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๋งŒ๋“ค๊ธฐ

// ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์šฉ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ
[AttributeUsage(AttributeTargets.Property)]
public class RequiredAttribute : Attribute
{
    public string ErrorMessage { get; set; }
    
    public RequiredAttribute(string errorMessage = "ํ•„์ˆ˜ ํ•ญ๋ชฉ์ž…๋‹ˆ๋‹ค.")
    {
        ErrorMessage = errorMessage;
    }
}

[AttributeUsage(AttributeTargets.Property)]
public class RangeAttribute : Attribute
{
    public int Min { get; set; }
    public int Max { get; set; }
    public string ErrorMessage { get; set; }
    
    public RangeAttribute(int min, int max)
    {
        Min = min;
        Max = max;
        ErrorMessage = $"๊ฐ’์€ {min}์—์„œ {max} ์‚ฌ์ด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.";
    }
}

// ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ์‚ฌ์šฉ
public class UserRegistration
{
    [Required("์‚ฌ์šฉ์ž ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค!")]
    public string Username { get; set; }
    
    [Required]
    public string Email { get; set; }
    
    [Range(18, 100)]
    public int Age { get; set; }
    
    public string PhoneNumber { get; set; }  // ์„ ํƒ ์‚ฌํ•ญ
}

๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ์ฝ๊ณ  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌํ•˜๊ธฐ โœ…

public class Validator
{
    public static List<string> Validate(object obj)
    {
        List<string> errors = new List<string>();
        Type type = obj.GetType();
        
        foreach (PropertyInfo prop in type.GetProperties())
        {
            // Required ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ํ™•์ธ
            var requiredAttr = prop.GetCustomAttribute<RequiredAttribute>();
            if (requiredAttr != null)
            {
                object value = prop.GetValue(obj);
                if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
                {
                    errors.Add($"{prop.Name}: {requiredAttr.ErrorMessage}");
                }
            }
            
            // Range ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ํ™•์ธ
            var rangeAttr = prop.GetCustomAttribute<RangeAttribute>();
            if (rangeAttr != null)
            {
                object value = prop.GetValue(obj);
                if (value is int intValue)
                {
                    if (intValue < rangeAttr.Min || intValue > rangeAttr.Max)
                    {
                        errors.Add($"{prop.Name}: {rangeAttr.ErrorMessage}");
                    }
                }
            }
        }
        
        return errors;
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
UserRegistration user = new UserRegistration
{
    Username = "",  // ๋น„์–ด์žˆ์Œ - ์—๋Ÿฌ!
    Email = "test@example.com",
    Age = 15  // ๋ฒ”์œ„ ๋ฐ– - ์—๋Ÿฌ!
};

List<string> errors = Validator.Validate(user);

if (errors.Count > 0)
{
    Console.WriteLine("โŒ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹คํŒจ:");
    foreach (string error in errors)
    {
        Console.WriteLine($"  โ€ข {error}");
    }
}
else
{
    Console.WriteLine("โœ… ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ†ต๊ณผ!");
}

// ์ถœ๋ ฅ:
// โŒ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹คํŒจ:
//   โ€ข Username: ์‚ฌ์šฉ์ž ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค!
//   โ€ข Age: ๊ฐ’์€ 18์—์„œ 100 ์‚ฌ์ด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๊ธฐ ๐ŸŽฏ

[Serializable]
[Obsolete("์ด ํด๋ž˜์Šค๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. NewPerson์„ ์‚ฌ์šฉํ•˜์„ธ์š”.")]
public class OldPerson
{
    public string Name { get; set; }
}

Type type = typeof(OldPerson);

// ๋ชจ๋“  ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ
object[] attributes = type.GetCustomAttributes(false);

Console.WriteLine($"์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๊ฐœ์ˆ˜: {attributes.Length}");

foreach (var attr in attributes)
{
    Console.WriteLine($"  โ€ข {attr.GetType().Name}");
    
    if (attr is ObsoleteAttribute obsolete)
    {
        Console.WriteLine($"    ๋ฉ”์‹œ์ง€: {obsolete.Message}");
    }
}

// ํŠน์ • ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋งŒ ํ™•์ธ
bool isSerializable = type.IsDefined(typeof(SerializableAttribute), false);
Console.WriteLine($"์ง๋ ฌํ™” ๊ฐ€๋Šฅ? {isSerializable}");  // True

๐Ÿ”ง Assembly ๋‹ค๋ฃจ๊ธฐ - DLL ๋™์  ๋กœ๋”ฉ

Assembly๋Š” .NET์˜ ๋ฐฐํฌ ๋‹จ์œ„์•ผ. DLL์ด๋‚˜ EXE ํŒŒ์ผ์ด์ง€! ๐Ÿ“ฆ
๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋Ÿฐํƒ€์ž„์— ์–ด์…ˆ๋ธ”๋ฆฌ๋ฅผ ๋กœ๋“œํ•˜๊ณ  ๊ทธ ์•ˆ์˜ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด.
ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ๋•Œ ํ•„์ˆ˜์ ์ธ ๊ธฐ์ˆ ์ด์•ผ! ๐Ÿ”Œ

// ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์–ด์…ˆ๋ธ”๋ฆฌ ๊ฐ€์ ธ์˜ค๊ธฐ
Assembly currentAssembly = Assembly.GetExecutingAssembly();
Console.WriteLine($"ํ˜„์žฌ ์–ด์…ˆ๋ธ”๋ฆฌ: {currentAssembly.FullName}");

// ํŠน์ • ํƒ€์ž…์ด ์†ํ•œ ์–ด์…ˆ๋ธ”๋ฆฌ ๊ฐ€์ ธ์˜ค๊ธฐ
Assembly stringAssembly = typeof(string).Assembly;
Console.WriteLine($"String์ด ์†ํ•œ ์–ด์…ˆ๋ธ”๋ฆฌ: {stringAssembly.GetName().Name}");

// ์–ด์…ˆ๋ธ”๋ฆฌ์—์„œ ๋ชจ๋“  ํƒ€์ž… ๊ฐ€์ ธ์˜ค๊ธฐ
Type[] types = currentAssembly.GetTypes();
Console.WriteLine($"\n๐Ÿ“š ์–ด์…ˆ๋ธ”๋ฆฌ ๋‚ด ํƒ€์ž… ๊ฐœ์ˆ˜: {types.Length}");

foreach (Type type in types.Take(10))  // ์ฒ˜์Œ 10๊ฐœ๋งŒ
{
    Console.WriteLine($"  โ€ข {type.FullName}");
}

// ํŠน์ • ์กฐ๊ฑด์˜ ํƒ€์ž…๋งŒ ํ•„ํ„ฐ๋ง
var publicClasses = types.Where(t => t.IsClass && t.IsPublic);
Console.WriteLine($"\n๊ณต๊ฐœ ํด๋ž˜์Šค ๊ฐœ์ˆ˜: {publicClasses.Count()}");

// ํŠน์ • ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ํƒ€์ž… ์ฐพ๊ธฐ
public interface IPlugin
{
    string Name { get; }
    void Execute();
}

var pluginTypes = types.Where(t => 
    typeof(IPlugin).IsAssignableFrom(t) && 
    !t.IsInterface && 
    !t.IsAbstract);

Console.WriteLine($"\n๐Ÿ”Œ ํ”Œ๋Ÿฌ๊ทธ์ธ ํƒ€์ž… ๊ฐœ์ˆ˜: {pluginTypes.Count()}");
foreach (var pluginType in pluginTypes)
{
    Console.WriteLine($"  โ€ข {pluginType.Name}");
}

์™ธ๋ถ€ DLL ๋™์ ์œผ๋กœ ๋กœ๋“œํ•˜๊ธฐ ๐Ÿš€

// ๋ฐฉ๋ฒ• 1: ํŒŒ์ผ ๊ฒฝ๋กœ๋กœ ๋กœ๋“œ
Assembly assembly = Assembly.LoadFrom(@"C:\Plugins\MyPlugin.dll");

// ๋ฐฉ๋ฒ• 2: ์–ด์…ˆ๋ธ”๋ฆฌ ์ด๋ฆ„์œผ๋กœ ๋กœ๋“œ (GAC๋‚˜ ์•ฑ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ๊ฒ€์ƒ‰)
Assembly assembly2 = Assembly.Load("MyPlugin, Version=1.0.0.0, Culture=neutral");

// ๋ฐฉ๋ฒ• 3: ๋ฐ”์ดํŠธ ๋ฐฐ์—ด๋กœ ๋กœ๋“œ (๋ฉ”๋ชจ๋ฆฌ์—์„œ)
byte[] assemblyBytes = File.ReadAllBytes(@"C:\Plugins\MyPlugin.dll");
Assembly assembly3 = Assembly.Load(assemblyBytes);

// ๋กœ๋“œ๋œ ์–ด์…ˆ๋ธ”๋ฆฌ์—์„œ ํƒ€์ž… ์ฐพ๊ธฐ
Type pluginType = assembly.GetType("MyPlugin.MainPlugin");

if (pluginType != null)
{
    // ํ”Œ๋Ÿฌ๊ทธ์ธ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
    object plugin = Activator.CreateInstance(pluginType);
    
    // IPlugin ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์บ์ŠคํŒ…
    if (plugin is IPlugin iPlugin)
    {
        Console.WriteLine($"ํ”Œ๋Ÿฌ๊ทธ์ธ ์ด๋ฆ„: {iPlugin.Name}");
        iPlugin.Execute();
    }
}

// ์–ด์…ˆ๋ธ”๋ฆฌ์˜ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค ๋‚˜์—ด
string[] resourceNames = assembly.GetManifestResourceNames();
Console.WriteLine("\n๐Ÿ“„ ์ž„๋ฒ ๋””๋“œ ๋ฆฌ์†Œ์Šค:");
foreach (string name in resourceNames)
{
    Console.WriteLine($"  โ€ข {name}");
}

ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ ๊ตฌํ˜„ ์˜ˆ์ œ ๐ŸŽฎ

public class PluginManager
{
    private List<IPlugin> _plugins = new List<IPlugin>();
    
    public void LoadPlugins(string pluginDirectory)
    {
        if (!Directory.Exists(pluginDirectory))
        {
            Console.WriteLine($"ํ”Œ๋Ÿฌ๊ทธ์ธ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค: {pluginDirectory}");
            return;
        }
        
        // ๋””๋ ‰ํ† ๋ฆฌ์˜ ๋ชจ๋“  DLL ํŒŒ์ผ ๊ฒ€์ƒ‰
        string[] dllFiles = Directory.GetFiles(pluginDirectory, "*.dll");
        
        foreach (string dllFile in dllFiles)
        {
            try
            {
                // DLL ๋กœ๋“œ
                Assembly assembly = Assembly.LoadFrom(dllFile);
                
                // IPlugin์„ ๊ตฌํ˜„ํ•œ ํƒ€์ž… ์ฐพ๊ธฐ
                var pluginTypes = assembly.GetTypes()
                    .Where(t => typeof(IPlugin).IsAssignableFrom(t) && 
                               !t.IsInterface && 
                               !t.IsAbstract);
                
                foreach (Type pluginType in pluginTypes)
                {
                    // ํ”Œ๋Ÿฌ๊ทธ์ธ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
                    IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);
                    _plugins.Add(plugin);
                    
                    Console.WriteLine($"โœ… ํ”Œ๋Ÿฌ๊ทธ์ธ ๋กœ๋“œ ์„ฑ๊ณต: {plugin.Name}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"โŒ {Path.GetFileName(dllFile)} ๋กœ๋“œ ์‹คํŒจ: {ex.Message}");
            }
        }
        
        Console.WriteLine($"\n์ด {_plugins.Count}๊ฐœ์˜ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ๋กœ๋“œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    }
    
    public void ExecuteAllPlugins()
    {
        Console.WriteLine("\n๐Ÿš€ ๋ชจ๋“  ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹คํ–‰:");
        foreach (var plugin in _plugins)
        {
            Console.WriteLine($"\n--- {plugin.Name} ---");
            plugin.Execute();
        }
    }
    
    public IPlugin GetPlugin(string name)
    {
        return _plugins.FirstOrDefault(p => 
            p.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
PluginManager manager = new PluginManager();
manager.LoadPlugins(@"C:\MyApp\Plugins");
manager.ExecuteAllPlugins();

// ํŠน์ • ํ”Œ๋Ÿฌ๊ทธ์ธ๋งŒ ์‹คํ–‰
IPlugin specificPlugin = manager.GetPlugin("DataProcessor");
specificPlugin?.Execute();
๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ™œ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ ์™ธ๋ถ€ DLL ๋™์  ๋กœ๋“œ ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ํ™•์žฅ ๋Ÿฐํƒ€์ž„ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๐Ÿ”Œ ORM ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐ์ฒด-DB ๋งคํ•‘ ์ž๋™ํ™” ํ”„๋กœํผํ‹ฐ ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ ์ƒ์„ฑ ๋™์  SQL ์ƒ์„ฑ ๐Ÿ—„๏ธ ์˜์กด์„ฑ ์ฃผ์ž… ์ž๋™ ๊ฐ์ฒด ์ƒ์„ฑ ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ ๋А์Šจํ•œ ๊ฒฐํ•ฉ ๐Ÿ’‰ ์ง๋ ฌํ™” ์‹œ์Šคํ…œ JSON/XML ๋ณ€ํ™˜ ํ”„๋กœํผํ‹ฐ ์ž๋™ ๋งคํ•‘ ์ปค์Šคํ…€ ์ปจ๋ฒ„ํ„ฐ ๐Ÿ“ฆ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ ์ž๋™ ํ…Œ์ŠคํŠธ ๊ฒ€์ƒ‰ Mock ๊ฐ์ฒด ์ƒ์„ฑ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๊ธฐ๋ฐ˜ ์‹คํ–‰ ๐Ÿงช API ์ž๋™ ์ƒ์„ฑ ์ปจํŠธ๋กค๋Ÿฌ ์ž๋™ ๋งคํ•‘ ๋ผ์šฐํŒ… ์„ค์ • ๋ฌธ์„œ ์ž๋™ ์ƒ์„ฑ ๐ŸŒ

โšก ์„ฑ๋Šฅ ์ตœ์ ํ™” - ๋ฆฌํ”Œ๋ ‰์…˜์€ ๋А๋ ค!

์†”์งํžˆ ๋งํ•˜๋ฉด, ๋ฆฌํ”Œ๋ ‰์…˜์€ ๋А๋ ค. ๐Ÿ˜…
์ผ๋ฐ˜์ ์ธ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋ณด๋‹ค 10๋ฐฐ์—์„œ 100๋ฐฐ๊นŒ์ง€ ๋А๋ฆด ์ˆ˜ ์žˆ์–ด.
ํ•˜์ง€๋งŒ ๊ฑฑ์ • ๋งˆ! ์ตœ์ ํ™” ๋ฐฉ๋ฒ•์ด ์žˆ๊ฑฐ๋“ . ๐Ÿ’ช

โš ๏ธ ๋ฆฌํ”Œ๋ ‰์…˜์ด ๋А๋ฆฐ ์ด์œ :

โ€ข ํƒ€์ž… ์ •๋ณด๋ฅผ ๋Ÿฐํƒ€์ž„์— ๊ฒ€์ƒ‰ํ•ด์•ผ ํ•จ
โ€ข ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž… ๊ฒ€์ฆ
โ€ข Boxing/Unboxing ์˜ค๋ฒ„ํ—ค๋“œ
โ€ข JIT ์ปดํŒŒ์ผ๋Ÿฌ ์ตœ์ ํ™” ๋ถˆ๊ฐ€
โ€ข ๋ณด์•ˆ ๊ฒ€์‚ฌ ์ˆ˜ํ–‰

์ตœ์ ํ™” ๋ฐฉ๋ฒ• 1: ์บ์‹ฑ ํ™œ์šฉ ๐Ÿ’พ

public class ReflectionCache
{
    private static Dictionary<string, MethodInfo> _methodCache 
        = new Dictionary<string, MethodInfo>();
    
    private static Dictionary<string, PropertyInfo> _propertyCache 
        = new Dictionary<string, PropertyInfo>();
    
    public static MethodInfo GetMethod(Type type, string methodName)
    {
        string key = $"{type.FullName}.{methodName}";
        
        if (!_methodCache.ContainsKey(key))
        {
            MethodInfo method = type.GetMethod(methodName);
            _methodCache[key] = method;
        }
        
        return _methodCache[key];
    }
    
    public static PropertyInfo GetProperty(Type type, string propertyName)
    {
        string key = $"{type.FullName}.{propertyName}";
        
        if (!_propertyCache.ContainsKey(key))
        {
            PropertyInfo property = type.GetProperty(propertyName);
            _propertyCache[key] = property;
        }
        
        return _propertyCache[key];
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
Type type = typeof(Person);

// ์ฒซ ๋ฒˆ์งธ ํ˜ธ์ถœ: ๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ๊ฒ€์ƒ‰ (๋А๋ฆผ)
MethodInfo method1 = ReflectionCache.GetMethod(type, "SayHello");

// ๋‘ ๋ฒˆ์งธ ํ˜ธ์ถœ: ์บ์‹œ์—์„œ ๊ฐ€์ ธ์˜ด (๋น ๋ฆ„!)
MethodInfo method2 = ReflectionCache.GetMethod(type, "SayHello");

์ตœ์ ํ™” ๋ฐฉ๋ฒ• 2: Delegate ์‚ฌ์šฉ ๐Ÿš€

// ๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ์ฐพ์€ ํ›„ Delegate๋กœ ๋ณ€ํ™˜
public class FastInvoker
{
    private static Dictionary<string, Delegate> _delegateCache 
        = new Dictionary<string, Delegate>();
    
    public static Func<T, TResult> CreateGetter<T, TResult>(string propertyName)
    {
        string key = $"{typeof(T).FullName}.{propertyName}";
        
        if (!_delegateCache.ContainsKey(key))
        {
            PropertyInfo property = typeof(T).GetProperty(propertyName);
            MethodInfo getMethod = property.GetGetMethod();
            
            // Delegate ์ƒ์„ฑ
            Func<T, TResult> getter = 
                (Func<T, TResult>)Delegate.CreateDelegate(
                    typeof(Func<T, TResult>), getMethod);
            
            _delegateCache[key] = getter;
        }
        
        return (Func<T, TResult>)_delegateCache[key];
    }
    
    public static Action<T, TValue> CreateSetter<T, TValue>(string propertyName)
    {
        string key = $"{typeof(T).FullName}.{propertyName}.Set";
        
        if (!_delegateCache.ContainsKey(key))
        {
            PropertyInfo property = typeof(T).GetProperty(propertyName);
            MethodInfo setMethod = property.GetSetMethod();
            
            Action<T, TValue> setter = 
                (Action<T, TValue>)Delegate.CreateDelegate(
                    typeof(Action<T, TValue>), setMethod);
            
            _delegateCache[key] = setter;
        }
        
        return (Action<T, TValue>)_delegateCache[key];
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
Person person = new Person("ํ…Œ์ŠคํŠธ", 25);

// Getter ์ƒ์„ฑ (ํ•œ ๋ฒˆ๋งŒ)
var nameGetter = FastInvoker.CreateGetter<Person, string>("Name");

// ์ดํ›„ ํ˜ธ์ถœ์€ ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋งŒํผ ๋น ๋ฆ„!
string name = nameGetter(person);  // ๋งค์šฐ ๋น ๋ฆ„!

// Setter ์ƒ์„ฑ
var nameSetter = FastInvoker.CreateSetter<Person, string>("Name");
nameSetter(person, "์ƒˆ ์ด๋ฆ„");  // ๋งค์šฐ ๋น ๋ฆ„!

์ตœ์ ํ™” ๋ฐฉ๋ฒ• 3: Expression Tree ์‚ฌ์šฉ ๐ŸŒณ

using System.Linq.Expressions;

public class ExpressionHelper
{
    public static Func<T> CreateConstructor<T>() where T : new()
    {
        // Expression Tree๋กœ ์ƒ์„ฑ์ž ํ˜ธ์ถœ ์ฝ”๋“œ ์ƒ์„ฑ
        NewExpression newExp = Expression.New(typeof(T));
        LambdaExpression lambda = Expression.Lambda<Func<T>>(newExp);
        
        // ์ปดํŒŒ์ผํ•ด์„œ Delegate๋กœ ๋ณ€ํ™˜
        return (Func<T>)lambda.Compile();
    }
    
    public static Func<object> CreateConstructor(Type type)
    {
        NewExpression newExp = Expression.New(type);
        LambdaExpression lambda = Expression.Lambda<Func<object>>(
            Expression.Convert(newExp, typeof(object)));
        
        return (Func<object>)lambda.Compile();
    }
    
    public static Func<T, TProperty> CreatePropertyGetter<T, TProperty>(
        string propertyName)
    {
        ParameterExpression parameter = Expression.Parameter(typeof(T), "obj");
        MemberExpression property = Expression.Property(parameter, propertyName);
        LambdaExpression lambda = Expression.Lambda<Func<T, TProperty>>(
            property, parameter);
        
        return (Func<T, TProperty>)lambda.Compile();
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
// ์ƒ์„ฑ์ž Delegate ์ƒ์„ฑ
var personFactory = ExpressionHelper.CreateConstructor<Person>();

// ์ด์ œ ๊ฐ์ฒด ์ƒ์„ฑ์ด new Person()๊ณผ ๊ฑฐ์˜ ๊ฐ™์€ ์†๋„!
Person p1 = personFactory();
Person p2 = personFactory();
Person p3 = personFactory();

// ํ”„๋กœํผํ‹ฐ Getter ์ƒ์„ฑ
var ageGetter = ExpressionHelper.CreatePropertyGetter<Person, int>("Age");
int age = ageGetter(p1);  // ๋งค์šฐ ๋น ๋ฆ„!

์„ฑ๋Šฅ ๋น„๊ต ๋ฒค์น˜๋งˆํฌ ๐Ÿ“Š

using System.Diagnostics;

public class PerformanceTest
{
    public static void ComparePerformance()
    {
        Person person = new Person("ํ…Œ์ŠคํŠธ", 30);
        int iterations = 1000000;
        Stopwatch sw = new Stopwatch();
        
        // 1. ์ผ๋ฐ˜ ํ˜ธ์ถœ
        sw.Start();
        for (int i = 0; i < iterations; i++)
        {
            string name = person.Name;
        }
        sw.Stop();
        Console.WriteLine($"์ผ๋ฐ˜ ํ˜ธ์ถœ: {sw.ElapsedMilliseconds}ms");
        
        // 2. ๋ฆฌํ”Œ๋ ‰์…˜ (์บ์‹ฑ ์—†์Œ)
        PropertyInfo prop = typeof(Person).GetProperty("Name");
        sw.Restart();
        for (int i = 0; i < iterations; i++)
        {
            object name = prop.GetValue(person);
        }
        sw.Stop();
        Console.WriteLine($"๋ฆฌํ”Œ๋ ‰์…˜ (์บ์‹ฑ ์—†์Œ): {sw.ElapsedMilliseconds}ms");
        
        // 3. ๋ฆฌํ”Œ๋ ‰์…˜ (์บ์‹ฑ ์žˆ์Œ)
        PropertyInfo cachedProp = ReflectionCache.GetProperty(typeof(Person), "Name");
        sw.Restart();
        for (int i = 0; i < iterations; i++)
        {
            object name = cachedProp.GetValue(person);
        }
        sw.Stop();
        Console.WriteLine($"๋ฆฌํ”Œ๋ ‰์…˜ (์บ์‹ฑ): {sw.ElapsedMilliseconds}ms");
        
        // 4. Delegate ์‚ฌ์šฉ
        var getter = FastInvoker.CreateGetter<Person, string>("Name");
        sw.Restart();
        for (int i = 0; i < iterations; i++)
        {
            string name = getter(person);
        }
        sw.Stop();
        Console.WriteLine($"Delegate: {sw.ElapsedMilliseconds}ms");
        
        // 5. Expression Tree
        var exprGetter = ExpressionHelper.CreatePropertyGetter<Person, string>("Name");
        sw.Restart();
        for (int i = 0; i < iterations; i++)
        {
            string name = exprGetter(person);
        }
        sw.Stop();
        Console.WriteLine($"Expression Tree: {sw.ElapsedMilliseconds}ms");
    }
}

// ์‹คํ–‰ ๊ฒฐ๊ณผ ์˜ˆ์‹œ:
// ์ผ๋ฐ˜ ํ˜ธ์ถœ: 5ms
// ๋ฆฌํ”Œ๋ ‰์…˜ (์บ์‹ฑ ์—†์Œ): 850ms
// ๋ฆฌํ”Œ๋ ‰์…˜ (์บ์‹ฑ): 720ms
// Delegate: 12ms
// Expression Tree: 8ms
๐Ÿ’ก ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ฐ€์ด๋“œ๋ผ์ธ:

โ€ข ๋ฆฌํ”Œ๋ ‰์…˜ ๊ฒฐ๊ณผ๋Š” ํ•ญ์ƒ ์บ์‹ฑํ•˜๊ธฐ
โ€ข ๋ฐ˜๋ณต ํ˜ธ์ถœ์ด ๋งŽ๋‹ค๋ฉด Delegate๋‚˜ Expression Tree ์‚ฌ์šฉ
โ€ข ์ดˆ๊ธฐํ™” ์‹œ์—๋งŒ ๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉํ•˜๊ณ , ๋Ÿฐํƒ€์ž„์—๋Š” ์บ์‹œ๋œ ์ •๋ณด ํ™œ์šฉ
โ€ข ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๋ถ€๋ถ„(์„ค์ • ๋กœ๋“œ ๋“ฑ)์—๋งŒ ์ง์ ‘ ๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ
โ€ข ํ”„๋กœํŒŒ์ผ๋ง์œผ๋กœ ๋ณ‘๋ชฉ ์ง€์  ํŒŒ์•… ํ›„ ์ตœ์ ํ™”

๐ŸŽจ ์‹ค์ „ ํ™œ์šฉ ์˜ˆ์ œ - JSON ์ง๋ ฌํ™” ๊ตฌํ˜„

์ด์ œ ๋ฐฐ์šด ๊ฑธ ์ข…ํ•ฉํ•ด์„œ ๊ฐ„๋‹จํ•œ JSON ์ง๋ ฌํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ? ๐Ÿ› ๏ธ
์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ API ์‘๋‹ต์„ ๋งŒ๋“ค ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์–ด!

using System.Text;

public class SimpleJsonSerializer
{
    public static string Serialize(object obj)
    {
        if (obj == null)
            return "null";
        
        Type type = obj.GetType();
        
        // ๊ธฐ๋ณธ ํƒ€์ž… ์ฒ˜๋ฆฌ
        if (type.IsPrimitive || type == typeof(string))
        {
            return SerializePrimitive(obj);
        }
        
        // ๋ฐฐ์—ด/๋ฆฌ์ŠคํŠธ ์ฒ˜๋ฆฌ
        if (obj is IEnumerable enumerable && type != typeof(string))
        {
            return SerializeEnumerable(enumerable);
        }
        
        // ๊ฐ์ฒด ์ฒ˜๋ฆฌ
        return SerializeObject(obj);
    }
    
    private static string SerializePrimitive(object obj)
    {
        if (obj is string str)
            return $"\"{str}\"";
        
        if (obj is bool b)
            return b.ToString().ToLower();
        
        return obj.ToString();
    }
    
    private static string SerializeEnumerable(IEnumerable enumerable)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("[");
        
        bool first = true;
        foreach (object item in enumerable)
        {
            if (!first)
                sb.Append(",");
            
            sb.Append(Serialize(item));
            first = false;
        }
        
        sb.Append("]");
        return sb.ToString();
    }
    
    private static string SerializeObject(object obj)
    {
        Type type = obj.GetType();
        PropertyInfo[] properties = type.GetProperties(
            BindingFlags.Public | BindingFlags.Instance);
        
        StringBuilder sb = new StringBuilder();
        sb.Append("{");
        
        bool first = true;
        foreach (PropertyInfo prop in properties)
        {
            // ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ํ”„๋กœํผํ‹ฐ๋งŒ
            if (!prop.CanRead)
                continue;
            
            if (!first)
                sb.Append(",");
            
            string propName = prop.Name;
            object propValue = prop.GetValue(obj);
            
            sb.Append($"\"{propName}\":");
            sb.Append(Serialize(propValue));
            
            first = false;
        }
        
        sb.Append("}");
        return sb.ToString();
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public bool InStock { get; set; }
    public List<string> Tags { get; set; }
}

Product product = new Product
{
    Id = 1,
    Name = "C# ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐ•์˜",
    Price = 50000,
    InStock = true,
    Tags = new List<string> { "ํ”„๋กœ๊ทธ๋ž˜๋ฐ", "C#", "์ดˆ๊ธ‰" }
};

string json = SimpleJsonSerializer.Serialize(product);
Console.WriteLine(json);

// ์ถœ๋ ฅ:
// {"Id":1,"Name":"C# ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐ•์˜","Price":50000,"InStock":true,"Tags":["ํ”„๋กœ๊ทธ๋ž˜๋ฐ","C#","์ดˆ๊ธ‰"]}

์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋กœ ์ง๋ ฌํ™” ์ œ์–ดํ•˜๊ธฐ ๐ŸŽ›๏ธ

[AttributeUsage(AttributeTargets.Property)]
public class JsonIgnoreAttribute : Attribute { }

[AttributeUsage(AttributeTargets.Property)]
public class JsonPropertyAttribute : Attribute
{
    public string Name { get; set; }
    
    public JsonPropertyAttribute(string name)
    {
        Name = name;
    }
}

public class User
{
    public int Id { get; set; }
    
    [JsonProperty("username")]
    public string Name { get; set; }
    
    public string Email { get; set; }
    
    [JsonIgnore]
    public string Password { get; set; }  // ์ง๋ ฌํ™”์—์„œ ์ œ์™ธ
    
    [JsonProperty("is_active")]
    public bool IsActive { get; set; }
}

// SimpleJsonSerializer ๊ฐœ์„ 
private static string SerializeObject(object obj)
{
    Type type = obj.GetType();
    PropertyInfo[] properties = type.GetProperties(
        BindingFlags.Public | BindingFlags.Instance);
    
    StringBuilder sb = new StringBuilder();
    sb.Append("{");
    
    bool first = true;
    foreach (PropertyInfo prop in properties)
    {
        if (!prop.CanRead)
            continue;
        
        // JsonIgnore ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ํ™•์ธ
        if (prop.GetCustomAttribute<JsonIgnoreAttribute>() != null)
            continue;
        
        if (!first)
            sb.Append(",");
        
        // JsonProperty ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋กœ ์ด๋ฆ„ ๋ณ€๊ฒฝ
        string propName = prop.Name;
        var jsonPropAttr = prop.GetCustomAttribute<JsonPropertyAttribute>();
        if (jsonPropAttr != null)
        {
            propName = jsonPropAttr.Name;
        }
        
        object propValue = prop.GetValue(obj);
        
        sb.Append($"\"{propName}\":");
        sb.Append(Serialize(propValue));
        
        first = false;
    }
    
    sb.Append("}");
    return sb.ToString();
}

// ์‚ฌ์šฉ
User user = new User
{
    Id = 100,
    Name = "ํ™๊ธธ๋™",
    Email = "hong@example.com",
    Password = "secret123",  // ์ง๋ ฌํ™”๋˜์ง€ ์•Š์Œ
    IsActive = true
};

string json = SimpleJsonSerializer.Serialize(user);
Console.WriteLine(json);

// ์ถœ๋ ฅ:
// {"Id":100,"username":"ํ™๊ธธ๋™","Email":"hong@example.com","is_active":true}

๐Ÿ” ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ

๋ฆฌํ”Œ๋ ‰์…˜์€ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๊ทธ๋งŒํผ ์œ„ํ—˜ํ•  ์ˆ˜๋„ ์žˆ์–ด! ๐Ÿšจ
private ๋ฉค๋ฒ„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑด ์บก์Аํ™”๋ฅผ ๊นจ๋œจ๋ฆด ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด๊ฑฐ๋“ .

โš ๏ธ ๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ:

1. ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ž…๋ ฅ ๊ฒ€์ฆ
์‚ฌ์šฉ์ž ์ž…๋ ฅ์œผ๋กœ ํƒ€์ž… ์ด๋ฆ„์ด๋‚˜ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ๋ฐ›์„ ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๊ฒ€์ฆ!

2. ๊ถŒํ•œ ํ™•์ธ
private ๋ฉค๋ฒ„ ์ ‘๊ทผ ์‹œ ์ •๋ง ํ•„์š”ํ•œ์ง€ ์žฌ๊ณ ํ•˜๊ธฐ

3. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
๋ฆฌํ”Œ๋ ‰์…˜์€ ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๊ฐ€ ๋งŽ์œผ๋‹ˆ ์ฒ ์ €ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•„์ˆ˜

4. ์„ฑ๋Šฅ ์˜ํ–ฅ
ํ•ซ ํŒจ์Šค(์ž์ฃผ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ)์—์„œ๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ ์ž์ œ

5. ํƒ€์ž… ์•ˆ์ •์„ฑ
์ปดํŒŒ์ผ ํƒ€์ž„ ํƒ€์ž… ์ฒดํฌ๋ฅผ ์šฐํšŒํ•˜๋ฏ€๋กœ ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ ๊ฐ€๋Šฅ์„ฑ ์ฆ๊ฐ€
// โŒ ๋‚˜์œ ์˜ˆ: ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ
public object InvokeMethod(string typeName, string methodName, object[] args)
{
    Type type = Type.GetType(typeName);  // ์œ„ํ—˜!
    MethodInfo method = type.GetMethod(methodName);  // ์œ„ํ—˜!
    return method.Invoke(null, args);
}

// โœ… ์ข‹์€ ์˜ˆ: ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๊ฒ€์ฆ
public object InvokeMethod(string typeName, string methodName, object[] args)
{
    // ํ—ˆ์šฉ๋œ ํƒ€์ž… ๋ชฉ๋ก
    var allowedTypes = new HashSet<string>
    {
        "MyApp.Calculator",
        "MyApp.StringHelper",
        "MyApp.DateHelper"
    };
    
    if (!allowedTypes.Contains(typeName))
    {
        throw new SecurityException($"ํƒ€์ž… '{typeName}'์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
    }
    
    Type type = Type.GetType(typeName);
    if (type == null)
    {
        throw new ArgumentException($"ํƒ€์ž… '{typeName}'์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
    }
    
    // ํ—ˆ์šฉ๋œ ๋ฉ”์„œ๋“œ ๋ชฉ๋ก
    var allowedMethods = new HashSet<string> { "Add", "Subtract", "Format" };
    
    if (!allowedMethods.Contains(methodName))
    {
        throw new SecurityException($"๋ฉ”์„œ๋“œ '{methodName}'์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
    }
    
    MethodInfo method = type.GetMethod(methodName);
    if (method == null)
    {
        throw new ArgumentException($"๋ฉ”์„œ๋“œ '{methodName}'์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
    }
    
    try
    {
        return method.Invoke(null, args);
    }
    catch (TargetInvocationException ex)
    {
        // ์‹ค์ œ ์˜ˆ์™ธ๋ฅผ ๋‹ค์‹œ ๋˜์ง€๊ธฐ
        throw ex.InnerException ?? ex;
    }
}

// ์•ˆ์ „ํ•œ ํ”„๋กœํผํ‹ฐ ์„ค์ •
public void SetPropertySafely<T>(T obj, string propertyName, object value)
{
    Type type = typeof(T);
    PropertyInfo property = type.GetProperty(propertyName);
    
    if (property == null)
    {
        throw new ArgumentException($"ํ”„๋กœํผํ‹ฐ '{propertyName}'์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
    }
    
    if (!property.CanWrite)
    {
        throw new InvalidOperationException($"ํ”„๋กœํผํ‹ฐ '{propertyName}'์€ ์ฝ๊ธฐ ์ „์šฉ์ž…๋‹ˆ๋‹ค.");
    }
    
    // ํƒ€์ž… ํ˜ธํ™˜์„ฑ ๊ฒ€์‚ฌ
    if (value != null && !property.PropertyType.IsAssignableFrom(value.GetType()))
    {
        throw new ArgumentException(
            $"๊ฐ’์˜ ํƒ€์ž…({value.GetType().Name})์ด ํ”„๋กœํผํ‹ฐ ํƒ€์ž…({property.PropertyType.Name})๊ณผ ํ˜ธํ™˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
    }
    
    try
    {
        property.SetValue(obj, value);
    }
    catch (Exception ex)
    {
        throw new InvalidOperationException(
            $"ํ”„๋กœํผํ‹ฐ '{propertyName}' ์„ค์ • ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ", ex);
    }
}

๐ŸŒŸ ๊ณ ๊ธ‰ ๊ธฐ๋ฒ• - ๋™์  ํƒ€์ž… ์ƒ์„ฑ

๋ฆฌํ”Œ๋ ‰์…˜์˜ ๋ํŒ์™•! ๋Ÿฐํƒ€์ž„์— ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! ๐ŸŽญ
System.Reflection.Emit ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด
IL(Intermediate Language) ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•ด์„œ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€.

using System.Reflection.Emit;

public class DynamicTypeBuilder
{
    public static Type CreateDynamicType(string typeName, 
        Dictionary<string, Type> properties)
    {
        // ๋™์  ์–ด์…ˆ๋ธ”๋ฆฌ ์ƒ์„ฑ
        AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
        AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
            assemblyName, AssemblyBuilderAccess.Run);
        
        // ๋™์  ๋ชจ๋“ˆ ์ƒ์„ฑ
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
        
        // ๋™์  ํƒ€์ž… ์ƒ์„ฑ
        TypeBuilder typeBuilder = moduleBuilder.DefineType(
            typeName,
            TypeAttributes.Public | TypeAttributes.Class);
        
        // ๊ฐ ํ”„๋กœํผํ‹ฐ ์ถ”๊ฐ€
        foreach (var prop in properties)
        {
            AddProperty(typeBuilder, prop.Key, prop.Value);
        }
        
        // ํƒ€์ž… ์™„์„ฑ
        return typeBuilder.CreateType();
    }
    
    private static void AddProperty(TypeBuilder typeBuilder, 
        string propertyName, Type propertyType)
    {
        // private ํ•„๋“œ ์ƒ์„ฑ
        FieldBuilder fieldBuilder = typeBuilder.DefineField(
            "_" + propertyName.ToLower(),
            propertyType,
            FieldAttributes.Private);
        
        // public ํ”„๋กœํผํ‹ฐ ์ƒ์„ฑ
        PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(
            propertyName,
            PropertyAttributes.HasDefault,
            propertyType,
            null);
        
        // Getter ๋ฉ”์„œ๋“œ ์ƒ์„ฑ
        MethodBuilder getterBuilder = typeBuilder.DefineMethod(
            "get_" + propertyName,
            MethodAttributes.Public | MethodAttributes.SpecialName | 
            MethodAttributes.HideBySig,
            propertyType,
            Type.EmptyTypes);
        
        ILGenerator getterIL = getterBuilder.GetILGenerator();
        getterIL.Emit(OpCodes.Ldarg_0);
        getterIL.Emit(OpCodes.Ldfld, fieldBuilder);
        getterIL.Emit(OpCodes.Ret);
        
        // Setter ๋ฉ”์„œ๋“œ ์ƒ์„ฑ
        MethodBuilder setterBuilder = typeBuilder.DefineMethod(
            "set_" + propertyName,
            MethodAttributes.Public | MethodAttributes.SpecialName | 
            MethodAttributes.HideBySig,
            null,
            new Type[] { propertyType });
        
        ILGenerator setterIL = setterBuilder.GetILGenerator();
        setterIL.Emit(OpCodes.Ldarg_0);
        setterIL.Emit(OpCodes.Ldarg_1);
        setterIL.Emit(OpCodes.Stfld, fieldBuilder);
        setterIL.Emit(OpCodes.Ret);
        
        // ํ”„๋กœํผํ‹ฐ์— getter/setter ์—ฐ๊ฒฐ
        propertyBuilder.SetGetMethod(getterBuilder);
        propertyBuilder.SetSetMethod(setterBuilder);
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
var properties = new Dictionary<string, Type>
{
    { "Id", typeof(int) },
    { "Name", typeof(string) },
    { "CreatedDate", typeof(DateTime) },
    { "IsActive", typeof(bool) }
};

Type dynamicType = DynamicTypeBuilder.CreateDynamicType("DynamicEntity", properties);

// ๋™์  ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
object instance = Activator.CreateInstance(dynamicType);

// ํ”„๋กœํผํ‹ฐ ์„ค์ •
PropertyInfo idProp = dynamicType.GetProperty("Id");
idProp.SetValue(instance, 123);

PropertyInfo nameProp = dynamicType.GetProperty("Name");
nameProp.SetValue(instance, "๋™์  ๊ฐ์ฒด");

PropertyInfo dateProp = dynamicType.GetProperty("CreatedDate");
dateProp.SetValue(instance, DateTime.Now);

// ํ”„๋กœํผํ‹ฐ ์ฝ๊ธฐ
Console.WriteLine($"Id: {idProp.GetValue(instance)}");
Console.WriteLine($"Name: {nameProp.GetValue(instance)}");
Console.WriteLine($"CreatedDate: {dateProp.GetValue(instance)}");

์ด ๊ธฐ๋ฒ•์€ ORM ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ํ”„๋ก์‹œ ๊ฐ์ฒด ์ƒ์„ฑ์— ์‚ฌ์šฉ๋ผ.
Entity Framework ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ์ด๋Ÿฐ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์ง€! ๐Ÿ”ฅ

๐ŸŽ“ ์‹ค๋ฌด ํ™œ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค

์ž, ์ด์ œ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š”์ง€ ๋ช‡ ๊ฐ€์ง€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋ณผ๊นŒ? ๐Ÿ’ผ

์‹œ๋‚˜๋ฆฌ์˜ค 1: ์„ค์ • ํŒŒ์ผ ์ž๋™ ๋ฐ”์ธ๋”ฉ โš™๏ธ

public class ConfigurationBinder
{
    public static T Bind<T>(Dictionary<string, string> config) where T : new()
    {
        T instance = new T();
        Type type = typeof(T);
        
        foreach (var kvp in config)
        {
            PropertyInfo property = type.GetProperty(kvp.Key, 
                BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            
            if (property != null && property.CanWrite)
            {
                try
                {
                    // ๋ฌธ์ž์—ด์„ ํ”„๋กœํผํ‹ฐ ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜
                    object value = Convert.ChangeType(kvp.Value, property.PropertyType);
                    property.SetValue(instance, value);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"'{kvp.Key}' ๋ฐ”์ธ๋”ฉ ์‹คํŒจ: {ex.Message}");
                }
            }
        }
        
        return instance;
    }
}

public class AppSettings
{
    public string DatabaseConnection { get; set; }
    public int MaxConnections { get; set; }
    public bool EnableLogging { get; set; }
    public double Timeout { get; set; }
}

// ์‚ฌ์šฉ
var configData = new Dictionary<string, string>
{
    { "DatabaseConnection", "Server=localhost;Database=MyDB" },
    { "MaxConnections", "100" },
    { "EnableLogging", "true" },
    { "Timeout", "30.5" }
};

AppSettings settings = ConfigurationBinder.Bind<AppSettings>(configData);

Console.WriteLine($"DB ์—ฐ๊ฒฐ: {settings.DatabaseConnection}");
Console.WriteLine($"์ตœ๋Œ€ ์—ฐ๊ฒฐ: {settings.MaxConnections}");
Console.WriteLine($"๋กœ๊น… ํ™œ์„ฑํ™”: {settings.EnableLogging}");
Console.WriteLine($"ํƒ€์ž„์•„์›ƒ: {settings.Timeout}์ดˆ");

์‹œ๋‚˜๋ฆฌ์˜ค 2: ๊ฐ„๋‹จํ•œ ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ ๐Ÿ’‰

public class SimpleContainer
{
    private Dictionary<Type, Type> _registrations = new Dictionary<Type, Type>();
    private Dictionary<Type, object> _singletons = new Dictionary<Type, object>();
    
    public void Register<TInterface, TImplementation>() 
        where TImplementation : TInterface
    {
        _registrations[typeof(TInterface)] = typeof(TImplementation);
    }
    
    public void RegisterSingleton<TInterface, TImplementation>() 
        where TImplementation : TInterface
    {
        Type interfaceType = typeof(TInterface);
        Type implementationType = typeof(TImplementation);
        
        _registrations[interfaceType] = implementationType;
        
        // ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
        object instance = CreateInstance(implementationType);
        _singletons[interfaceType] = instance;
    }
    
    public T Resolve<T>()
    {
        return (T)Resolve(typeof(T));
    }
    
    private object Resolve(Type type)
    {
        // ์‹ฑ๊ธ€ํ†ค ํ™•์ธ
        if (_singletons.ContainsKey(type))
        {
            return _singletons[type];
        }
        
        // ๋“ฑ๋ก๋œ ํƒ€์ž… ํ™•์ธ
        if (_registrations.ContainsKey(type))
        {
            Type implementationType = _registrations[type];
            return CreateInstance(implementationType);
        }
        
        // ๊ตฌ์ฒด ํƒ€์ž…์ด๋ฉด ์ง์ ‘ ์ƒ์„ฑ
        if (!type.IsAbstract && !type.IsInterface)
        {
            return CreateInstance(type);
        }
        
        throw new InvalidOperationException($"ํƒ€์ž… '{type.Name}'์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
    }
    
    private object CreateInstance(Type type)
    {
        // ์ƒ์„ฑ์ž ์ฐพ๊ธฐ (๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๊ฐ€์žฅ ๋งŽ์€ ๊ฒƒ)
        ConstructorInfo[] constructors = type.GetConstructors();
        ConstructorInfo constructor = constructors
            .OrderByDescending(c => c.GetParameters().Length)
            .First();
        
        // ์ƒ์„ฑ์ž ๋งค๊ฐœ๋ณ€์ˆ˜ ํ•ด๊ฒฐ
        ParameterInfo[] parameters = constructor.GetParameters();
        object[] parameterInstances = new object[parameters.Length];
        
        for (int i = 0; i < parameters.Length; i++)
        {
            parameterInstances[i] = Resolve(parameters[i].ParameterType);
        }
        
        // ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
        return constructor.Invoke(parameterInstances);
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
public interface ILogger
{
    void Log(string message);
}

public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine($"[LOG] {message}");
    }
}

public interface IDataService
{
    void SaveData(string data);
}

public class DataService : IDataService
{
    private readonly ILogger _logger;
    
    public DataService(ILogger logger)
    {
        _logger = logger;
    }
    
    public void SaveData(string data)
    {
        _logger.Log($"๋ฐ์ดํ„ฐ ์ €์žฅ ์ค‘: {data}");
        // ์‹ค์ œ ์ €์žฅ ๋กœ์ง...
    }
}

// ์ปจํ…Œ์ด๋„ˆ ์„ค์ •
SimpleContainer container = new SimpleContainer();
container.RegisterSingleton<ILogger, ConsoleLogger>();
container.Register<IDataService, DataService>();

// ์˜์กด์„ฑ ์ž๋™ ์ฃผ์ž…!
IDataService dataService = container.Resolve<IDataService>();
dataService.SaveData("์ค‘์š”ํ•œ ์ •๋ณด");  // [LOG] ๋ฐ์ดํ„ฐ ์ €์žฅ ์ค‘: ์ค‘์š”ํ•œ ์ •๋ณด

์‹œ๋‚˜๋ฆฌ์˜ค 3: ๊ฐ์ฒด ๋ณต์‚ฌ(Deep Clone) ๐Ÿ”„

public class ObjectCloner
{
    public static T DeepClone<T>(T source)
    {
        if (source == null)
            return default(T);
        
        Type type = typeof(T);
        
        // ๊ฐ’ ํƒ€์ž…์ด๋‚˜ string์€ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜
        if (type.IsValueType || type == typeof(string))
            return source;
        
        // ์ƒˆ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
        T clone = Activator.CreateInstance<T>();
        
        // ๋ชจ๋“  ํ•„๋“œ ๋ณต์‚ฌ (private ํฌํ•จ)
        FieldInfo[] fields = type.GetFields(
            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        
        foreach (FieldInfo field in fields)
        {
            object fieldValue = field.GetValue(source);
            
            if (fieldValue != null)
            {
                // ์ฐธ์กฐ ํƒ€์ž…์ด๋ฉด ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์‚ฌ
                if (field.FieldType.IsClass && field.FieldType != typeof(string))
                {
                    MethodInfo cloneMethod = typeof(ObjectCloner)
                        .GetMethod("DeepClone")
                        .MakeGenericMethod(field.FieldType);
                    
                    fieldValue = cloneMethod.Invoke(null, new[] { fieldValue });
                }
                
                field.SetValue(clone, fieldValue);
            }
        }
        
        return clone;
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
public class Address
{
    public string City { get; set; }
    public string Street { get; set; }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Address Address { get; set; }
}

Person original = new Person
{
    Name = "๊น€์ฒ ์ˆ˜",
    Age = 30,
    Address = new Address { City = "์„œ์šธ", Street = "๊ฐ•๋‚จ๋Œ€๋กœ" }
};

Person cloned = ObjectCloner.DeepClone(original);

// ๋ณต์‚ฌ๋ณธ ์ˆ˜์ •
cloned.Name = "์ด์˜ํฌ";
cloned.Address.City = "๋ถ€์‚ฐ";

Console.WriteLine($"์›๋ณธ: {original.Name}, {original.Address.City}");  
// ์ถœ๋ ฅ: ์›๋ณธ: ๊น€์ฒ ์ˆ˜, ์„œ์šธ

Console.WriteLine($"๋ณต์‚ฌ๋ณธ: {cloned.Name}, {cloned.Address.City}");  
// ์ถœ๋ ฅ: ๋ณต์‚ฌ๋ณธ: ์ด์˜ํฌ, ๋ถ€์‚ฐ

๐Ÿš€ ์žฌ๋Šฅ๋„ท์—์„œ ๋ฆฌํ”Œ๋ ‰์…˜ ํ™œ์šฉํ•˜๊ธฐ

์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์„ ๊ฐœ๋ฐœํ•œ๋‹ค๋ฉด ๋ฆฌํ”Œ๋ ‰์…˜์„ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์„๊นŒ? ๐Ÿค”
๋ช‡ ๊ฐ€์ง€ ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž!

์žฌ๋Šฅ ์นดํ…Œ๊ณ ๋ฆฌ ์ž๋™ ๋“ฑ๋ก ์‹œ์Šคํ…œ ๐Ÿ“‹

// ์žฌ๋Šฅ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์–ดํŠธ๋ฆฌ๋ทฐํŠธ
[AttributeUsage(AttributeTargets.Class)]
public class TalentCategoryAttribute : Attribute
{
    public string CategoryName { get; set; }
    public string Description { get; set; }
    public int DisplayOrder { get; set; }
    
    public TalentCategoryAttribute(string categoryName)
    {
        CategoryName = categoryName;
    }
}

// ์žฌ๋Šฅ ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค
public interface ITalentService
{
    string GetServiceName();
    decimal GetPrice();
    void Execute();
}

// ๊ตฌ์ฒด์ ์ธ ์žฌ๋Šฅ ์„œ๋น„์Šค๋“ค
[TalentCategory("ํ”„๋กœ๊ทธ๋ž˜๋ฐ", Description = "์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ๊ด€๋ จ", DisplayOrder = 1)]
public class CSharpTutorService : ITalentService
{
    public string GetServiceName() => "C# ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ณผ์™ธ";
    public decimal GetPrice() => 50000;
    public void Execute() => Console.WriteLine("C# ๊ฐ•์˜๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค!");
}

[TalentCategory("๋””์ž์ธ", Description = "๊ทธ๋ž˜ํ”ฝ ๋””์ž์ธ", DisplayOrder = 2)]
public class LogoDesignService : ITalentService
{
    public string GetServiceName() => "๋กœ๊ณ  ๋””์ž์ธ";
    public decimal GetPrice() => 100000;
    public void Execute() => Console.WriteLine("๋กœ๊ณ  ๋””์ž์ธ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค!");
}

[TalentCategory("๋ฒˆ์—ญ", Description = "์–ธ์–ด ๋ฒˆ์—ญ ์„œ๋น„์Šค", DisplayOrder = 3)]
public class TranslationService : ITalentService
{
    public string GetServiceName() => "์˜ํ•œ ๋ฒˆ์—ญ";
    public decimal GetPrice() => 30000;
    public void Execute() => Console.WriteLine("๋ฒˆ์—ญ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค!");
}

// ์žฌ๋Šฅ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ - ์ž๋™์œผ๋กœ ๋ชจ๋“  ์žฌ๋Šฅ ์„œ๋น„์Šค ๊ฒ€์ƒ‰
public class TalentRegistry
{
    private List<Type> _talentServices = new List<Type>();
    
    public void ScanAssembly()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        
        // ITalentService๋ฅผ ๊ตฌํ˜„ํ•œ ๋ชจ๋“  ํƒ€์ž… ์ฐพ๊ธฐ
        var serviceTypes = assembly.GetTypes()
            .Where(t => typeof(ITalentService).IsAssignableFrom(t) && 
                       !t.IsInterface && 
                       !t.IsAbstract);
        
        _talentServices.AddRange(serviceTypes);
        
        Console.WriteLine($"๐Ÿ” {_talentServices.Count}๊ฐœ์˜ ์žฌ๋Šฅ ์„œ๋น„์Šค๋ฅผ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค!\n");
    }
    
    public void DisplayAllTalents()
    {
        // ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ ๊ทธ๋ฃนํ™”
        var groupedByCategory = _talentServices
            .Select(t => new
            {
                Type = t,
                Attribute = t.GetCustomAttribute<TalentCategoryAttribute>()
            })
            .Where(x => x.Attribute != null)
            .GroupBy(x => x.Attribute.CategoryName)
            .OrderBy(g => g.First().Attribute.DisplayOrder);
        
        foreach (var category in groupedByCategory)
        {
            Console.WriteLine($"๐Ÿ“‚ ์นดํ…Œ๊ณ ๋ฆฌ: {category.Key}");
            Console.WriteLine($"   ์„ค๋ช…: {category.First().Attribute.Description}\n");
            
            foreach (var item in category)
            {
                ITalentService service = (ITalentService)Activator.CreateInstance(item.Type);
                
                Console.WriteLine($"   โœจ {service.GetServiceName()}");
                Console.WriteLine($"      ๊ฐ€๊ฒฉ: {service.GetPrice():N0}์›");
                Console.WriteLine($"      ํƒ€์ž…: {item.Type.Name}\n");
            }
        }
    }
    
    public ITalentService CreateService(string serviceName)
    {
        Type serviceType = _talentServices
            .FirstOrDefault(t =>
            {
                ITalentService temp = (ITalentService)Activator.CreateInstance(t);
                return temp.GetServiceName().Equals(serviceName, 
                    StringComparison.OrdinalIgnoreCase);
            });
        
        if (serviceType != null)
        {
            return (ITalentService)Activator.CreateInstance(serviceType);
        }
        
        return null;
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
TalentRegistry registry = new TalentRegistry();
registry.ScanAssembly();
registry.DisplayAllTalents();

// ํŠน์ • ์„œ๋น„์Šค ์‹คํ–‰
ITalentService service = registry.CreateService("C# ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ณผ์™ธ");
if (service != null)
{
    Console.WriteLine($"\n๐ŸŽฏ '{service.GetServiceName()}' ์„œ๋น„์Šค๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค!");
    service.Execute();
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ƒˆ๋กœ์šด ์žฌ๋Šฅ ์„œ๋น„์Šค๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ๋งˆ๋‹ค
์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋งŒ ๋ถ™์ด๋ฉด ์ž๋™์œผ๋กœ ์‹œ์Šคํ…œ์— ๋“ฑ๋ก๋ผ! ๐Ÿ˜Ž
์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ์ˆ˜๋ฐฑ ๊ฐœ์˜ ์„œ๋น„์Šค๋ฅผ ๊ด€๋ฆฌํ•  ๋•Œ ์ •๋ง ์œ ์šฉํ•˜์ง€!

๐Ÿ’ก ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค์™€ ํŒ

โœ… ๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ ์‹œ ๊ถŒ์žฅ์‚ฌํ•ญ:

1. ์บ์‹ฑ์€ ํ•„์ˆ˜
Type, MethodInfo, PropertyInfo ๋“ฑ์€ ํ•œ ๋ฒˆ ๊ฐ€์ ธ์˜ค๋ฉด ์บ์‹ฑํ•˜๊ธฐ

2. BindingFlags ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •
๊ธฐ๋ณธ๊ฐ’์— ์˜์กดํ•˜์ง€ ๋ง๊ณ  ํ•„์š”ํ•œ ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ช…ํ™•ํžˆ ์ง€์ •

3. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ฒ ์ €ํžˆ
TargetInvocationException์˜ InnerException ํ™•์ธ

4. ์„ฑ๋Šฅ ์ธก์ •
๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ ์ „ํ›„ ์„ฑ๋Šฅ ๋น„๊ต ํ•„์ˆ˜

5. ๋Œ€์•ˆ ๊ณ ๋ ค
์ œ๋„ค๋ฆญ, ์ธํ„ฐํŽ˜์ด์Šค, Delegate ๋“ฑ์œผ๋กœ ํ•ด๊ฒฐ ๊ฐ€๋Šฅํ•œ์ง€ ๋จผ์ € ๊ฒ€ํ† 

6. ๋ฌธ์„œํ™”
์™œ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ–ˆ๋Š”์ง€ ์ฃผ์„์œผ๋กœ ๋ช…ํ™•ํžˆ ์„ค๋ช…

7. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
๋ฆฌํ”Œ๋ ‰์…˜ ์ฝ”๋“œ๋Š” ์ปดํŒŒ์ผ ํƒ€์ž„ ์ฒดํฌ๊ฐ€ ์•ˆ ๋˜๋ฏ€๋กœ ํ…Œ์ŠคํŠธ ํ•„์ˆ˜

8. ๋ฒ„์ „ ๊ด€๋ฆฌ
์–ด์…ˆ๋ธ”๋ฆฌ ๋ฒ„์ „์ด ๋ฐ”๋€Œ๋ฉด ํƒ€์ž… ์ด๋ฆ„๋„ ๋ฐ”๋€” ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฃผ์˜
๐ŸŽฏ ์–ธ์ œ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ?

์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์€ ๊ฒฝ์šฐ:
โ€ข ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ ๊ตฌํ˜„
โ€ข ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฐœ๋ฐœ
โ€ข ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™”
โ€ข ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ
โ€ข ์ฝ”๋“œ ์ƒ์„ฑ ๋„๊ตฌ
โ€ข ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ

ํ”ผํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ:
โ€ข ์ผ๋ฐ˜์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
โ€ข ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ํ•ซ ํŒจ์Šค
โ€ข ์ปดํŒŒ์ผ ํƒ€์ž„์— ํƒ€์ž…์„ ์•Œ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ
โ€ข ๊ฐ„๋‹จํ•œ ๊ฐ์ฒด ์ƒ์„ฑ์ด๋‚˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ

๐ŸŽฌ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์ž, ์—ฌ๊ธฐ๊นŒ์ง€ C# ๋ฆฌํ”Œ๋ ‰์…˜๊ณผ ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•ด ์•Œ์•„๋ดค์–ด! ๐ŸŽ‰
์ฒ˜์Œ์—” ์–ด๋ ต๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ•œ ๋ฒˆ ์ต์ˆ™ํ•ด์ง€๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๊ฐ€ ๋ผ.

๋ฆฌํ”Œ๋ ‰์…˜์€ ๋งˆ์น˜ ํ”„๋กœ๊ทธ๋žจ์˜ X-ray ๊ฐ™์•„.
์ฝ”๋“œ์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๋“ค์—ฌ๋‹ค๋ณด๊ณ , ๋Ÿฐํƒ€์ž„์— ๋™์ ์œผ๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์ง€.
ํ•˜์ง€๋งŒ ๊ฐ•๋ ฅํ•œ ๋งŒํผ ์‹ ์ค‘ํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ด! โšก

์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์„ ๊ฐœ๋ฐœํ•˜๊ฑฐ๋‚˜, ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜,
์œ ์—ฐํ•œ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•  ๋•Œ ๋ฆฌํ”Œ๋ ‰์…˜์€ ์ •๋ง ์œ ์šฉํ•œ ์นœ๊ตฌ๊ฐ€ ๋  ๊ฑฐ์•ผ.
์„ฑ๋Šฅ๊ณผ ์œ ์—ฐ์„ฑ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ์ž˜ ๋งž์ถ”๋ฉด์„œ ํ™œ์šฉํ•ด๋ณด์ž! ๐Ÿ’ช

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค๋ฅธ ์œ ์šฉํ•œ ์ง€์‹๋“ค๋„ ์ฐพ์•„๋ณด๊ณ ,
๋„ˆ์˜ ์žฌ๋Šฅ๋„ ๊ณต์œ ํ•ด๋ณด๋Š” ๊ฑด ์–ด๋•Œ? ๐Ÿ˜Š
์šฐ๋ฆฌ ๋ชจ๋‘ ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์ž! ๐Ÿš€

๐ŸŒŸ Happy Coding! ๐ŸŒŸ

๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ๋” ์œ ์—ฐํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด๋ณด์„ธ์š”!
์งˆ๋ฌธ์ด๋‚˜ ํ”ผ๋“œ๋ฐฑ์€ ์–ธ์ œ๋“  ํ™˜์˜์ž…๋‹ˆ๋‹ค! ๐Ÿ’ฌ
๋ฆฌํ”Œ๋ ‰์…˜ ๋งˆ์Šคํ„ฐ ๋กœ๋“œ๋งต ๊ธฐ์ดˆ Type ๊ฐ์ฒด ๋ฉค๋ฒ„ ์ •๋ณด ์ค‘๊ธ‰ ๋™์  ํ˜ธ์ถœ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ๊ณ ๊ธ‰ ์„ฑ๋Šฅ ์ตœ์ ํ™” Emit ์‹ค์ „ ํ”„๋ ˆ์ž„์›Œํฌ ํ”Œ๋Ÿฌ๊ทธ์ธ ๐Ÿ† ๋งˆ์Šคํ„ฐ!
๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.