본문 바로가기

C#/C# 문법

C# Func와 Action 대리자

728x90
728x90

이 포스트에서는 델리게이트를 사용케 하는 또 다른 문법 Func와 Action에 대해 알아보도록 한다. 둘 다 위임을 하는 경우가 있고 delegate와 용어가 겹치므로 이전에 배운 대리자는 delegate, Func와 Action에 대해선 대리자라 부르겠다.

Func

Func는 반환형이 존재하는 non void delegate로 볼 수 있다. Func 대리자는 다음과 같은 구조를 가지고 있다.

Func<매개변수1, 매개변수2, ... 매개변수16, 반환형> myDelegate;

Func는 <> 꺾새 안에 최대 16개의 매개변수를 설정할 수 있으며 마지막에는 Func 대리자의 반환형을 명시해야 한다.

 

참고로 매개변수를 받지 않는 Func 대리자는 반환형만 명시하면 된다.

Func<반환형> myDelegate;

 

Func 대리자에 원하는 메서드를 넣으려면 람다식을 넣거나 메서드 자체를 대입하면 된다.

// 1. myFunc에 곧바로 람다식을 대입
Func<int, int, int> myFunc = (int a, int b) => {
    return a * b;
};

 

// 2. Func에 메서드 자체를 대입
public static int getPlus(int a, int b)
{
    return a + b;
}

Func<int, int, int> myFunc = getPlus;

 

Func 대리자에 위임된 메서드는 언제든지 같은 매개변수와 같은 반환형을 같은 다른 메서드로 교체할 수 있다.

namespace Course
{
    class Program
    {
        public static int getPlus(int a, int b)
        {
            return a + b;
        }

        static void Main(string[] args)
        {
            Func<int, int, int> myFunc = (int a, int b) => {
                return a * b;
            };

            int result = myFunc(100, 100);
            Console.WriteLine(result);
            
            // myFunc를 null로 비워준 뒤 getPlus를 넣어 더하기 메서드로 바꿨다.
            myFunc = null;
            myFunc = getPlus;
            Console.WriteLine(myFunc(99, 1));
        }
    }
}

이렇게 Func 대리자는 기존의 delegate와 다르게 새 delegate 객체를 만들지 않고도 간단하게 사용할 수 있다.

Action

Action은 반환형이 존재하지 않는 대리자이다. Func 대리자와 비교해 반환형을 넣지 않는 차이가 있다.

Action<매개변수1, ... 매개변수16> myAction1;
Action myAction2; // void는 꺾새를 넣지 않는다.

 

사용 방법도 Func와 완전히 똑같다. Func를 사용할 때 예시처럼 해주면 된다.

Chaining

물론 Func나 Action도 여러 메서드를 위임할 수 있다. +, - 연산자로 넣고 싶은 메서드를 더하고 싶은 만큼 더할 수 있다.

 

물론 Func 대리자는 이전 포스트에서 다룬 delegate와 마찬가지로 맨 마지막으로 더해진 메서드의 반환 값이 나옴을 유의하도록 하자.

그래서 이거 왜 쓰는데요?

이전 포스트에서 delegate chaining으로 여러 메서드를 한꺼번에 호출하는 기능을 살펴봤었다. 하지만 이것만으로도 사용 의의에 대한 의문이 해소되지 않을 수 있다. 이 문단에서는 대리자를 쓰면 편리한 상황을 언급하고자 한다.

 

public Action<PointerEventData> OnDragHandler = null;
public Action<PointerEventData> OnClickHandler = null;

/*
...
*/

UI_EventHandler evt = Util.GetOrAddComponent<UI_EventHandler>(go);

// type과 action은 메서드의 인자로 들어옴
switch (type)
{
    case Define.UIEvent.Click:
        evt.OnClickHandler -= action;
        evt.OnClickHandler += action;
        break;
    case Define.UIEvent.Drag:
        evt.OnDragHandler -= action;
        evt.OnDragHandler += action;
        break;
}

 

다음 코드는 type의 종류에 따라 조건에 해당하는 Action 대리자에게 인자로 action 메서드를 위임한다. 이렇게 항상 실행되는 메서드가 있고 거기에 특정 상황을 만족할 때마다 의도한 메서드를 실행시키도록 하고 싶을 때 대리자를 전달하는 방법이 있다.

 

이런 방법은 특정 상황에 따라 일일이 메서드를 호출할 위치에 찾아가 메서드를 호출하지 않고 그저 대리자에게 전달만 하고 대리자를 호출하도록 하면 메서드를 호출하는 코드를 간결하게 짤 수 있다.

 

그 외에도 스택 오버플로우에서는 Func와 Action을 언제 쓰는지에 대한 몇 가지 예시를 보여주니 참고하면 좋을 것이다. 링크로 건 글에서는 Func와 Action 말고도 Predicate라는 것이 있는데 Func가 Predicate의 발전된 형태로 나온 것이라 무시해도 좋다.

 

지금까지 C#의 델리게이트 개념을 이해하고 실제로 위임하는 방법인 Func와 Action에 대해 배웠다. 아직 C# 배우는 단계라면 이 둘의 사용이 어색할 수 있지만 프로젝트를 진행하다 보면 매우 유용하게 사용될 수 있으니 사용방법을 잊지 말도록 하자!

728x90
728x90

'C# > C# 문법' 카테고리의 다른 글

C# delegate (델리게이트, 대리자) 기초  (0) 2022.02.06
C# 확장 메서드 Extension Method  (0) 2022.01.02
C# ref와 out의 차이  (0) 2022.01.01