[C#] IEnumerable, Linq 사용 예제

유니티에서 Foreach 를 실행시 Garbage를 생성시키는것을 피하기위해서 주로 사용 했었는데, 근래에는 Foreach를 사용해도 Garbage를 생성 하지 않는다 한다.

다음목표

  1. IEnumerable 를 어떤 케이스에서 쓰는게 효율적일지 생각해보자.
  2. Linq 는 어떤 상황일때 쓰는게 좋을지 생각해보자.
using UnityEngine;
using System.Collections;
using System.Collections.Generic; // IEnumerable 쓰려고.
using System.Linq;

public class Bong9_Enumerable : MonoBehaviour {

	// Use this for initialization
	void Start () {

        ///
        /// string 객체에는 IEnumerable 인터페이스가 구현 되어있다.
        /// 

        string[] strList = { "bong9", "bong8", "bong7", "b09", "b08", "b07" };

        // 구현.
        Debug.Log("------IEnumerable() Start ------");
        IEnumerable(strList);
        Debug.Log("------IEnumerable() End ------");

        // Linq 사용.
        Debug.Log("------IEnumerable_Linq() Start ------");
        IEnumerable_Linq(strList);
        Debug.Log("------IEnumerable_Linq() End ------");
	}

    void IEnumerable_Linq(string[] strList)
    {
        // 조건 : 글자수가 3개 이하.
        IEnumerable enumerable = from str in strList where str.Length <= 3 select str;

        IEnumerator e = enumerable.GetEnumerator();

        while (e.MoveNext())
        {
            Debug.Log(e.Current);
        }
    }

    void IEnumerable(string[] strList)
    {
        IEnumerator e = strList.GetEnumerator();

        while (e.MoveNext())
        {
            Debug.Log(e.Current);
        }
        // Debug.Log(e.Current); // 이미 열거가 완료되어 에러.

        e.Reset(); // 열거 초기화.
        e.MoveNext();
        Debug.Log(e.Current + "열거 초기화 후 다시 출력.");
    }

	// Update is called once per frame
	void Update () {

	}
}

[C#] Action 과 Delegate, 람다식, Action, Func, Event

  •  Delegate ( 위임자 )
    • 일종의 함수 포인터
    • 내부적으로 Count 만큼 List를 순회하는 연결리스트 구조를 생성
  • Action의 정의
    • Action은 반환값과 인자값이 없는 함수 포인터 ( 델리게이트 )
    • 반환 형식이 없음
    • 어떤 결과를 반환하는것을 목적으로 하지 않으며, 일련의 작업 수행을 목적
/* Action 델리게이트 예제 */
    void Start()
    {
        Action act1 = () => Debug.Log("Action()");
        act1();

        int re = 0;
        Action act2 = (x) => re = x * x; // 람다식 밖에서 선언한 re에 결과값 저장.
        act2(3);

        Debug.Log("re : " + re);

        Action act3 = (x, y) =>
        {
            double pi = x / y;
            Debug.Log("Action(" + x + ", " + y + ") : " + pi);
        };

        act3(22.0, 7.0);
    }
using System.Runtime.CompilerServices;

namespace System
{
      public delegate void Action();
}
  • Func ( 델리게이트 )
    • 일종의 함수 포인터
    • 내부적으로 Count 만큼 List를 순회하는 연결리스트 구조를 생성
    • 익명메소드, 무명함수를 만들기위해서는 항상 델리게이트를 선언 해야 하지만 Func를 사용하면 끝

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

public class Tester : MonoBehaviour {

    public Action myAction;

    public void SetAction(Action func)
    {
        myAction += func;
    }

    public static void Func1() { Debug.Log("Func1 실행"); }
    public static void Func2() { Debug.Log("Func2 실행"); }

    // SetAction으로 함수를 등록한후,
    void Start()
    {
        Tester ActionTest = new Tester();
        ActionTest.SetAction(Func1);
        ActionTest.SetAction(Func2);
        ActionTest.myAction();
    }
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;

public class Tester : MonoBehaviour {

    public delegate int Print (string msg );

    public static int SpeakA(string msg)
    {
        Debug.Log("A : " + msg);
        return 0;
    }
    public static int SpeakB(string msg)
    {
        Debug.Log("B : " + msg);
        return 1;
    }

    void Start()
    {
        Print A = new Print(SpeakA);
        //Print B = new Print(SpeakB);

        A("Hello");
        //B("Hello");
    }
}
void Start()
    {
        Func func1 = () => 10;             // 바로 10을 리턴.
        Func func2 = (x) => x * 2;         // 넣어준 인수의 2를 곱한값 리턴.
        Action act = (x) =>                // 리턴없는 Action 함수.
        {
            Debug.Log(x);                  // Debug.Log로 직접 출력.
        };

        Debug.Log(func1());
        Debug.Log(func2(3));
        act(10);
    }
/* 람다식 (Lambda expression) 선언 예제 */
    delegate int Calculate(int a, int b);
    delegate void DoSomething();

    void Start()
    {
        Calculate cal = (a, b) => a + b;
        Debug.Log(cal(1, 3));

        DoSomething Doit = () =>
        {
            Debug.Log("두잇.");
        };

        Doit();
    }

/* 익명메소드를 이용한 델리게이트 사용 */
    delegate string Fire(string location);

    void Start()
    {
        Fire fire;
        fire = delegate(string location)
        {
            return location;
        };

        Debug.Log(fire("here"));
    }

/* 델리게이트 체인 */
    delegate void MyFire(string location);

    public static void call119(string location)
    {
        Debug.Log("불난곳: " + location);
    }

    public static void shout(string location)
    {
        Debug.Log("소리친곳: " + location);
    }

    public static void escape(string location)
    {
        Debug.Log("도망가는곳: " + location);
    }

    void Start()
    {
        MyFire fire = new MyFire(call119);

        fire += new MyFire(call119);    // 첫번째 델리게이트 체인 등록.
        fire += new MyFire(shout);      // 두번째 델리게이트 체인 등록.
        fire += new MyFire(escape);     // 세번째 델리게이트 체인 등록.

        fire("우리집에서");              // 함수포인터(델리게이트)에 등록이된 함수들을 실행.
    }
/* 문형식의 람다식 */

    string[] args = { "hi", "hello", "good" };

    delegate string Co(string[] args);

    void Start()
    {
        Co c = (arr) =>
        {
            string re = "";
            foreach (string s in arr)
            {
                re += s;
                Debug.Log("Add string is " + s);
            }
            return re;
        };
        Debug.Log(c(args));
    }
  • Event
    • 이벤트는 델리게이트에 event 한정자를 수식해서 선언한것에 불과하다
    • 이벤트와 델리게이트의 차이점은 이벤트는 public으로 선언되어 있어도 외부에서 사용할 수 가 없다.
    • 델리게이트는 public, internal로 수식되어 있으면 클래스 외부에서도 얼마든지 호출이 가능하다
    /* 이벤트, 델리게이트 예제 01 */
    delegate void EventCaller(string m);

    class CallEvent
    {
        public event EventCaller ec;
    }

    void Start()
    {
        CallEvent callEvent = new CallEvent();
        //callEvent.ec("test"); // 에러, 이벤트는 객체 외부에서 직접 호출 할 수 없다.
    }
/* 이벤트, 델리게이트 예제 02 */
    delegate void EventHandler(string m);

    class Notification
    {
        public event EventHandler eventHandler;

        public void EvenOdd(int number)
        {
            int temp = number % 10;

            if (temp != 0 && temp % 3 == 0)
            {
                eventHandler(string.Format("{0} : Even", number));
            }
        }
    }

    public static void MEventHandler(string m)
    {
        Debug.Log(m);
    }

    public static void SEventHandler(string m)
    {
        Debug.Log(m + "SEvebtHandler");
    }

    public static void XEventHandler(string m)
    {
        Debug.Log(m + "XEvebtHandler");
    }

    void Start()
    {
        Notification noti = new Notification();
        noti.eventHandler += new EventHandler(MEventHandler);
        noti.eventHandler += new EventHandler(SEventHandler);
        noti.eventHandler += new EventHandler(XEventHandler);

        for (int i = 1; i < 30; i++)
        {
            noti.EvenOdd(i);
        }
    }