(C# : Basic) 5. 추가 문법

Posted by : at

Category : CSharp


Generic (일반화)

object obj = 3;
object obj2 = "hello world";

int num = (int)obj;
string str = (string)obj2;

// var와 차이점은?
// var는 컴파일러가 컴파일타임제 데이터형을 지정해 준다.
// object는 자료형의 최상위 부모이다.
// generic class
class MyList<T>
{
    T[] arr = new T[10];

    public T GetItem(int i)
    {
        return arr[i];
    }
}

// Main
MyList<int> myIntList = MyList<int>();
MyList<float> myIntList = MyList<float>();

함수 일반화도 가능

static void Test<T>(int input)
{

}

Test<int>(3);
Test<float>(3);

generic의 조건도 지정이 가능하다

class MyList<T> where T : new() // 기본생성자를 무조건 포함해달라
class MyList<T> where T : class  // class로 생성되어야 한다.
class MyList<T> where T : struct // struct로 생성되어야 한다.
class MyList<T> where T : Monster // Monster 클래스의 자녀여야 한다.

Interface

// 추상클래스
class Monster
{
    // 자녀 클래스에서 Shout를 무조건 만들게 할 순 없나?
    public virtual void Shout() {}
}
// Monster자체를 abstract로 만든다.
abstract class Monster
{
    public abstract void Shout();    // 함수의 내용이 있으면 안됨
}

class Orc : Monster
{
    public override void Shout()
    {

    }
}
abstract class Flyable
{
    public abstract void Fly();
}

class FlyableOrc : Orc, Flyable // Error : C#은 다중상속 지원 안함
interface IFlyable
{
    void Fly();
}

class FlyableOrc : Orc, IFlyable
{
    public void Fly() {}        // Okay
}

Property

class Knight
{
    private int hp;

    public int GetHp() { return hp; }
    public void SetHp(int hp) { this.hp = hp; }
}

좀 더 편하게 할순 없나?

class Knight
{
    private int hp;

    public int Hp
    {
        get { return hp; }
        /*private (지정가능)*/set { this.hp = value; }
    }
}

// 사용은
Knight knight = new Knight();
knight.Hp = 100;
int _hp = knight.Hp;

더 펀하게는??

class Knight
{
    public int Hp
    {
        get; set;
    } = 100;    // 초기화도 가능
}

Delegate

delegate int OnClicked();

static void ButtonPressed(OnClicked Func)
{
    Func();
}

static int TestDelegate()
{
    Console.WriteLine("Hello");
}

static int TestDelegate2()
{
    Console.WriteLine("Hello2");
}

static void Main(string[] args)
{
    ButtonPressed(TestDelegate);

    // 이런것도 가능
    OnClicked clicked = new OnClicked(TestDelegate);
    clicked += TestDelegate2;

    ButtonPressed(clicked); // 두 개의 Delegate가 모두 호출된다.
}

Event

class InputManager
{
    public delegate void OnInputKey();
    public event OnInputKey InputKey;

    public void Update()
    {
        // 키 입력을 확인
        if(Console.KeyAvailable == false)
            return;

        ConsoleKeyInfo info = Console.ReadKey();
        if(info.Key == ConsoleKey.A)
        {
            // 모두에게 알려주자
            InputKey();
        }
    }
}

// ...

// Main
static void OnInputTest()
{

}

static void Main(string[] args)
{
    InputManager inputManager = new InputManager();

    // 이벤트 연결
    inputManager.InputKey +=OnInputTest;

    while(true)
    {
        inputManager.Update();
    }
}

Action

static void Main(string[] args)
{
    // 1. 기존 메서드 지정
    Action<string> _action1 = Print;
    _action1("action1");

    // 2. 무명 메서드 지정
    Action<string, string> _action2 = delegate(string msg, string error)
    {
        Console.WriteLine(msg, error);
    };
    _action2("action2", "inform");

    // 3. 람다식 사용
    Action<int, int> _action3 = (x, y) => {
        Console.WriteLine("{0} + {1} = {2}", x, y, x + y);
    };
}

public static void Print(string msg)
{
    Console.WriteLine(msg);
}

Lambda

enum ItemType
{
    Weapon,
    Armor,
    Amulet,
    Ring
}

enum Rarity
{
    Normal,
    Uncommon,
    Rare
}

class Item
{
    public ItemType ItemType;
    public Rarity Rarity;
}

class Program
{
    static List<Item> _items = new List<Item>();

    // 모든 조건에 따라 Find함수를 만들어야하나?
    // Rare도 만들고 이후에 조건이 추가되면 또 만들고???
    static Item FindWeapon()
    {
        foreach(Item item in _items)
        {
            if(item.ItemType == ItemType.Weapon)
                return item
        }

        return null;
    }

    static void Main(string[] args)
    {
        _items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
        _items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
        _items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });
    }
}
class Program
{
    static List<Item> _items = new List<Item>();

    // delegate이용해보기
    delegate bool ItemSelector(Item item);

    // 여전히 단점은 아래와 같은 판별 함수를 만들어 줘야한다는 점.
    static bool IsWeapon(Item item)
    {
        return item.ItemType == ItemTypeWeapon;
    }

    static Item FindItem(ItemSelector selector)
    {
        foreach(Item item in _items)
        {
            if(selector(item))
                return item
        }
        return null;
    }

    static void Main(string[] args)
    {
        _items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
        _items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
        _items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });

        Item item = FindItem(IsWeapon);
    }
}
class Program
{
    static List<Item> _items = new List<Item>();

    delegate bool ItemSelector(Item item);

    static Item FindItem(ItemSelector selector)
    {
        foreach(Item item in _items)
        {
            if(selector(item))
                return item
        }
        return null;
    }

    static void Main(string[] args)
    {
        _items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
        _items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
        _items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });

        // 아래와 같이 무명함수로 처리가능(람다식과는 다름)
        Item item = FindItem(delegate (Item item) {
            return item.ItemType == ItemTypeWeapon;
        }));
    }
}
class Program
{
    static List<Item> _items = new List<Item>();

    delegate bool ItemSelector(Item item);

    static Item FindItem(ItemSelector selector)
    {
        foreach(Item item in _items)
        {
            if(selector(item))
                return item
        }
        return null;
    }

    static void Main(string[] args)
    {
        _items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
        _items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
        _items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });

        // 람다식
        Item item = FindItem((Item item) => {
            return item.ItemType == ItemTypeWeapon;
        }));
    }
}

추가

class Program
{
    static List<Item> _items = new List<Item>();

    // delegate Retrun MyFunc<T, Retrun>(T item);
    // 이걸 C#에서 자체 지원함 Func로 사용하면 된다.
        // 참고로 void리턴은 Action을 사용하면 됨.

    // static Item FindItem(MyFunc<Item, bool> selector)
    static Item FindItem(Func<Item, bool> selector)
    {
        foreach(Item item in _items)
        {
            if(selector(item))
                return item
        }
        return null;
    }

    static void Main(string[] args)
    {
        _items.Add(new Item() { ItemType = ItemType.Weapon, Rarity = Rarity.Normal });
        _items.Add(new Item() { ItemType = ItemType.Armor, Rarity = Rarity.Uncommon });
        _items.Add(new Item() { ItemType = ItemType.Amulet, Rarity = Rarity.Rare });

        // MyFunc<Item, bool> selector = (Item item) => { return item.ItemType == ItemTypeWeapon; };
        Func<Item, bool> selector = (Item item) => { return item.ItemType == ItemTypeWeapon; };

        Item item = FindItem(selector);
    }
}

Exception

try
{
    // * 0으로 나누는 경우
    int a = 5;
    int b = 0;
    int result = a / b;

    // * 잘못된 메모리 참조
    // * 오버플로

}
catch(DivideByZeroException e)
{
    // * 0으로 나누는 경우
}
catch(Exception e)
{
    // exception 내부에 예외상황에 대한 설명이 나와있음
}
finally
{
    // catch이후 과정을 넣음
}

Reflection

X-Ray를 찍는효과

class Monster
{
    public int hp;
    protected int attack;
    private float speed;

    void Attack() {}
}

// Main
Monster monster = new Monster();
Type type = monster.GetType();      // GetType은 C#의 object아래 있음
var fields = type.GetFields(BindingFlags.Public);   
// 런타임에 Monster 내부의 변수/함수를 확인가능

Nullable



About Taehyung Kim

안녕하세요? 8년차 현업 C++ 개발자 김태형이라고 합니다. 😁 C/C++을 사랑하며 다양한 사람과의 협업을 즐깁니다. ☕ 꾸준한 자기개발을 미덕이라 생각하며 노력중이며, 제가 얻은 지식을 홈페이지에 정리 중입니다. 좀 더 상세한 제 이력서 혹은 Private 프로젝트 접근 권한을 원하신다면 메일주세요. 😎

Star
Useful Links