본문 바로가기

C#

C# 문법 _ 델리게이트(delegate), 람다식, 제네릭

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 델리게이트( delegate 대리자 )
// 함수 자체를 인자로 넘겨주는 기능

// 이벤트 ( event )
// 외부에서 멋대로 호출할 수 있어서 한번 더 매핑해준 것이 event

public class DelegateTest : MonoBehaviour
{
    // 반환 : int
    // 입력 : void
    // 이름 : OnClicked

    delegate int OnClicked();


    void ButtonPressed(OnClicked clicked) // OnClicked 델리게이트와 반환형, 입력값이 같은 메소드들만 넣어줄 수 있음 !!!
    {
        clicked();
    }

    int DeleTest()
    {
        Debug.Log("DeleTest");
        return 0;
    }

    int DeleTest_Two()
    {
        Debug.Log("Hello");
        return 0;
    }

    void OnInputKeyTest()
    {
        Debug.Log("OnInputKeyTest");
    }

    private void Start()
    {
        // ========================================================================
        // 델리게이트 예시
        OnClicked onclick = new OnClicked(DeleTest);
        onclick += DeleTest_Two; // 체이닝 ( 차례대로 호출됨 )    
        onclick(); // 내부적으로 호출

        // 델리게이트의 문제점 : 아무데서나 호출됨
        // 이에 대응하여 
        // 이벤트가 생겨남 ( 델리게이트를 한번 더 랩핑해 줌)

        // ========================================================================
        // 이벤트 예시

        InputManager inputManager = new InputManager();
        inputManager.InputKey += OnInputKeyTest; // 구독

        // 델리게이트와 달리 외부에서 호출하려고 하면 에러 발생 !!!
        // inputManager.InputKey();

        // 유일하게 할 수 있는건 구독신청해서 실행하는 것
        // 이벤트 구독은 외부에서 해줘야하기에 public event ~~ 형식임
        // 이벤트 호출은 InputManager 클래스에서만 가능 !!

        
    }
}

 

익명함수

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 람다식 (lambda)
// 일회용 함수를 만드는데 사용

enum ItemType // 타입
{
    Weapon,
    Armor,
    Amulet,
    Ring
}

enum ItemRarity // 등급
{
    Rare,
    Epic,
    Legend
}

class Item
{
    public ItemType type;
    public ItemRarity rarity; 
}

public class LambdaTest : MonoBehaviour
{
    List<Item> items = new List<Item>();

    delegate bool ItemSelector(Item item); // 반환:bool , 입력:Item class
    
    void Start()
    {
        items.Add(new Item() { type = ItemType.Weapon, rarity = ItemRarity.Rare });
        items.Add(new Item() { type = ItemType.Armor, rarity = ItemRarity.Epic });
        items.Add(new Item() { type = ItemType.Amulet, rarity = ItemRarity.Legend });


        Item item0 = FindItem(IsWeapon);

        // 무명함수, 익명함수 _ 초창기 c# 문법
        Item item1 = FindItem( delegate (Item item) { return item.type == ItemType.Weapon; } );
        
        // 람다식 (입력)=>{ 구현 & 반환 }
        Item item2 = FindItem( (Item item) => { return item.type == ItemType.Weapon; } );
        
        // 중괄호와 return과 세미콜론 생략
        Item item3 = FindItem( (Item item) => item.type == ItemType.Weapon );
        
        // 매개변수의 타입 생략
        Item item4 = FindItem( (item) => item.type == ItemType.Weapon );

        // 입력변수의 소괄호 생략
        Item item5 = FindItem( item => item.type == ItemType.Weapon );


        ItemSelector selector = new ItemSelector(item => item.type == ItemType.Weapon);
        Item item6 = FindItem(selector);
    }

    bool IsWeapon(Item item)
    {
        return item.type == ItemType.Weapon;
    }

    Item FindItem(ItemSelector select)
    {
        foreach (var item in items)
        {
            if (select(item))
            {
                return item;
            }
        }
        return null;
    }

   
    Item FindWeapon()
    {
        foreach(var item in items)
        {
            if (item.type == ItemType.Weapon)
            {
                return item;
            }
        }
        return null;
    }

    Item FindLegend()
    {
        foreach (var item in items)
        {
            if (item.rarity == ItemRarity.Legend)
            {
                return item;
            }
        }
        return null;
    }
}

 

제네릭 적용

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 람다식 (lambda)
// 일회용 함수를 만드는데 사용

enum ItemType // 타입
{
    Weapon,
    Armor,
    Amulet,
    Ring
}

enum ItemRarity // 등급
{
    Rare,
    Epic,
    Legend
}

class Item
{
    public ItemType type;
    public ItemRarity rarity; 
}

public class LambdaTest : MonoBehaviour
{
    List<Item> items = new List<Item>();

    delegate bool ItemSelector<T>(T item); // 반환:bool , 입력:Item class

    delegate R MyFunc<T, R>(T item); // 반환:R(return) , 입력:T(type) // 공용 델리게이트 // 인자 1개
    delegate R MyFunc<T1, T2, R>(T1 t1, T2 t2); // 반환:R(return) , 입력:T1 T2(type) // 공용 델리게이트 // 인자 2개
    delegate R MyFunc<T1, T2, T3, R>(T1 t1, T2 t2, T3 t3); // 반환:R(return) , 입력:T1 T2 T3(type) // 공용 델리게이트 // 인자 2개
    // 위의 코드들은 c#에서 Func이라는 명칭으로 이미 제공해주는 델리게이트들
    // Func< ~ > 
    // Func는 반환값( 제네릭 R )이 있는! 델리게이트

    // Action< ~ >
    // Action 은 반환값이 없는! 델리게이트
    
    
    void Start()
    {
        items.Add(new Item() { type = ItemType.Weapon, rarity = ItemRarity.Rare });
        items.Add(new Item() { type = ItemType.Armor, rarity = ItemRarity.Epic });
        items.Add(new Item() { type = ItemType.Amulet, rarity = ItemRarity.Legend });


        Item item0 = FindItem(IsWeapon);

        // 무명함수, 익명함수 _ 초창기 c# 문법
        Item item1 = FindItem( delegate (Item item) { return item.type == ItemType.Weapon; } );
        
        // 람다식 (입력)=>{ 구현 & 반환 }
        Item item2 = FindItem( (Item item) => { return item.type == ItemType.Weapon; } );
        
        // 중괄호와 return과 세미콜론 생략
        Item item3 = FindItem( (Item item) => item.type == ItemType.Weapon );
        
        // 매개변수의 타입 생략
        Item item4 = FindItem( (item) => item.type == ItemType.Weapon );

        // 입력변수의 소괄호 생략
        Item item5 = FindItem( item => item.type == ItemType.Weapon );


        ItemSelector<Item> selector = new ItemSelector<Item>(item => item.type == ItemType.Weapon);
        Item item6 = FindItem(selector);
    }

    bool IsWeapon(Item item)
    {
        return item.type == ItemType.Weapon;
    }

    //
    Item FindItem(ItemSelector<Item> select)
    {
        foreach (var item in items)
        {
            if (select(item))
            {
                return item;
            }
        }
        return null;
    }


    Item FindItemGeneric(MyFunc<Item, bool> select)
    {
        foreach (var item in items)
        {
            if (select(item))
            {
                return item;
            }
        }
        return null;
    }

    Item FindItemGeneric(Func<Item, bool> select)
    {
        foreach (var item in items)
        {
            if (select(item))
            {
                return item;
            }
        }
        return null;
    }
}