2016년 12월 6일 화요일

Action과 Func

C#에서는 delegate를 사용해서 여러가지 작업을 할 수 있습니다.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegate
{
    class Program
    {
        private static void Plus(int a, int b)
        {
            Console.WriteLine("{0} + {1} = {2}", a, b, a + b);
        }
        private static void Minus(int a, int b)
        {
            Console.WriteLine("{0} - {1} = {2}", a, b, a - b);
        }
        private static void Multiply(int a, int b)
        {
            Console.WriteLine("{0} * {1} = {2}", a, b, a * b);
        }
        private static void Divide(int a, int b)
        {
            if(b != 0)
                Console.WriteLine("{0} / {1} = {2}", a, b, a / b);
        }
        private delegate void Function(int a, int b);
        static void Main(string[] args)
        {
            Function f = null;
            f += Plus;
            f += Minus;
            f += Multiply;
            f += Divide;
            f(1, 2);
            Console.WriteLine("-----------");
            f(2, 1);
            Console.WriteLine("-----------");
            f(3, 0);
        }
    }
}

인수 두개를 요구하는 함수를 Function으로 정의해 놓고, Function인 f를 만든 후, f에 Plus, Minus 등의 함수를 등록시키면, f를 한번 호출하는 것으로 등록된 함수들을 모두 호출할 수 있습니다.

그런데 사실 이런 일을 하기 위해서는 delegate를 사용할 필요도 없습니다. 이미 필요한 함수들이 정의되어 있기 때문입니다. Action<>이 바로 이미 정의된 delegate들입니다.,
바로 System에 다음과 같이 정의되어 있습니다.

namespace System
{
    public delegate void Action();
    public delegate void Action<in T1>(T1 arg1);
    public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
    public delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T3 arg3);
    public delegate void Action<in T1, in T2, in T3, in T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12arg12, T13 arg13);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
}

위와같이 16개의 인수를 가질 수 있는 함수까지 만들어져 있습니다(사실 이렇게까지 많이 만들 필요는 없을것 같습니다만....)

그러므로 만약 위 프로그램을 Action으로 만든다면 다음과 같습니다.

        // private delegate void Function(int a, int b); 딜리게이트 제거
        static void Main(string[] args)
        {
            Action<int, int> f = null;  // delegate 대신 인수가 int 2개인 Action 선언
            f += Plus;
            f += Minus;
            f += Multiply;
            f += Divide;
            f(1, 2);
            Console.WriteLine("-----------");
            f(2, 1);
            Console.WriteLine("-----------");
            f(3, 0);
        }

최초의 프로그램과 완전히 똑같은 결과가 나오죠.


이와 거의 동일하게 Func<> 역시 존재합니다. Func는 리턴값까지 있는 delegate를 대신합니다.

        private static string Plus(int a, int b)
        {
            return string.Format("{0} + {1} = {2}", a, b, a + b);
        }
        private static string Minus(int a, int b)
        {
            return string.Format("{0} - {1} = {2}", a, b, a - b);
        }

        static void Main(string[] args)
        {
            Func<int, int, string> f = null; // int 2개를 인수로 하고 string을 리턴하는 함수 선언
            f += Plus;
            f += Minus;
            Console.WriteLine(f(1, 2));
            Console.WriteLine(f(2, 1));
        }

단, 이 경우에는 f에 등록된 함수들 중 가장 마지막으로 실행된 함수의 리턴값만이 남게 됩니다. 이점을 주의해야 합니다.

댓글 없음:

댓글 쓰기