센로그

[C#] Delegate(대리자) - delegate, Func, Action, Predicate 본문

게임/Unity, C#

[C#] Delegate(대리자) - delegate, Func, Action, Predicate

seeyoun 2023. 7. 3. 15:03

◆ Delegate

함수를 담는 변수

 

C#에서 Delegate는 특정 형식의 메서드를 참조할 수 있는 타입이다.

말 그대로 메서드의 '대리자' 역할을 한다.

C++의 함수 포인터와 유사하다.

 

다음과 같이, delegate 리턴타입 델리게이트명(파라미터) 형식으로 선언한다.

delegate void Calculator(int a, int b);

델리게이트는 같은 반환형 및 같은 매개변수를 갖는 함수를 담을 수 있다.

위의 델리게이트 Caculator는 반환형이 void이고, 파라미터로 (int, int)를 받는 함수를 담을 수 있다.

 

예시) 다음 코드 실행시 3이 출력된다.

delegate void Calculator(int a, int b);

static void Plus(int a, int b)
{
    Console.WriteLine(a + b);
}
        
static void Main(string[] args)
{
    Calculator calc = Plus;
    calc(1,2);
}

 


◆ Delegate parameter

다음과 같이, 델리게이트를 통해 메서드를 매개변수로 전달할 수 있다.

delegate void Calculator(int a, int b);

static void Plus(int a, int b)
{
    Console.WriteLine(a + b);
}

static void Minus(int a, int b)
{
    Console.WriteLine(a - b);
}

static void MyCalc(Calculator calc, int a, int b)	// delegate를 파라미터로 받음
{
    calc(a, b);
}

 

이 경우, 메인에서 다음과 같이 Calculator을 바꿔가며 계산할 수 있다.

static void Main(string[] args)
{
    Calculator calc = Plus;
    MyCalc(calc, 1, 2); //3

    calc = Minus;
    MyCalc(calc, 1, 2); //-1
}

 


◆ C# 내장 delegate

많이 쓰이는 형식에 대해서는, C#에서 미리 정의해둔 델리게이트들이 존재한다. 

다음 종류의 내장 델리게이트가 있다. (T와 Tresult는 제네릭 타입)

  • Func<T, Tresult>
  • Action<T>
  • Predicate<T>

이런 델리게이트들은 .NET 프레임워크 메서드들의 파라미터로 많이 사용된다.

Func은 LINQ에서 많이 사용되고, Predicate는 Array나 List의 메서드들에서 많이 사용된다.

 


◆ Func delegate

Func<T, Tresult>
: 파라미터 T를 받아서 Tresult를 리턴하는 델리게이트

T는 파라미터의 제네릭형 타입(여러개 가능. Func<T1, T2, ..., Tresult>)
Tresult(마지막 제네릭)은 반환형의 제네릭형 타입

 

다음과 같이 (int, int)를 받아 string을 반환하는 함수가 있다고 하자.

string Plus(int a, int b)
{
	return (a + b).ToString(); 
}

 

이를 내장 델리게이트 Func으로 받아서 쓰려면 다음과 같이 작성한다.

static void Main(string[] args)
{
    Func<int, int, string> func = Plus;
    Console.WriteLine(func(1, 2));  //3
}

위 func에서 앞의 두개의 int는 파라미터의 타입이고, 마지막 int는 리턴 타입을 의미한다.

 

 

Func는 LINQ에서 Where 조건 판별시 많이 사용된다.

 


◆ Action delegate

Action<T>
: 파라미터 T를 받고, 반환형이 없는(void) 델리게이트

T는 파라미터의 제네릭형 타입(여러개 가능. Action<T1, T2, ..., Tn>)

 

다음과 같이 (int, int)를 받고 반환형이 없는 함수가 있다고 하자.

static void Plus(int a, int b)
{
    Console.WriteLine(a + b);
}

 

이를 내장 델리게이트 Action으로 받아서 쓰려면 다음과 같이 작성한다.

static void Main(string[] args)
{
    Action<int, int> action = Plus;
    action(1,2); //3
}

위 action에서 int, int는 모두 파라미터의 타입을 의미한다.

 

 

Console.WriteLine같은 메서드 역시 다음과 같이 대리자를 통해 호출할 수 있다.

Action<string> print = Console.WriteLine;
print("3");	//3

 


◆ Predicate delegate

Predicate<T>
: T를 받아서 Boolean을 리턴하는 델리게이트

T는 파라미터의 제네릭형 타입(여러개 불가능)

 

List나 Array 메서드에서 사용됨.

 

List 클래스 메서드

https://learn.microsoft.com/ko-kr/dotnet/api/system.collections.generic.list-1?view=net-7.0 

 

Array 클래스 메서드

https://learn.microsoft.com/ko-kr/dotnet/api/system.array?view=net-7.0 

 


◆ Delegate Chain

하나의 델리게이트에 여러개의 함수를 연결하여 연쇄적으로 호출하는 것

 

다음과 같은 델리게이트 void Calculator(int, int)plus(), minus(), multiply(), divide() 함수가 있다고 하자.

delegate void Calculator(int a, int b);


public static void plus(int a, int b)
{
    Console.WriteLine(a + b);
}

public static void minus(int a, int b)
{
    Console.WriteLine(a - b);
}

public static void multiply(int a,int b)
{
    Console.WriteLine(a * b);
}

public static void divide(int a, int b)
{
    Console.WriteLine(a / b);
}

 

이를 연결해서 한번에 호출하고 싶다면 다음과 같이 Delegate.Combine()을 사용한다.

public static void Main(string[] args)
{
    //델리게이트 체인
    Calculator calc = (Calculator)Delegate.Combine(new Calculator(plus), new Calculator(minus), new Calculator(multiply), new Calculator(divide));
    calc(20, 10);
}

 

출력


Delegate Multicast

Delegate Chain을 통해서 한번에 메서드들을 연결할 수도 있지만, += 또는 -= 연산자를 사용해 메서드 연결을 추가하거나 뺄 수도 있다. 이를 Delegate Multicast라고 부른다.

public static void Main(string[] args)
{
    Calculator calculators = plus;
    calculators += minus;
    calculators += multiply;
    calculators += divide;
    calculators(20, 10);
}

 

출력

 


◆ Delegate + Lambda

델리게이트는 람다식과 함께 쓰곤한다.

람다식은  (매개변수) => {메서드 본문}  형식으로 이루어져있다.

 

간단한 예시)

public static void Main(string[] args)
{
    //델리게이트 + 람다
    Calculator calculator0 = (a, b) => Console.WriteLine(a + b);
    calculator0(20, 10);
    
    //Func 델리게이트 + 람다
    Func<int, int, string> calculator1 = (a, b) => (a + b).ToString();
    Console.WriteLine(calculator1(20, 10));
    
    //Action 델리게이트 + 람다
    Action<int, int> calculator2 = (a, b) => Console.WriteLine(a + b);
    calculator2(20, 10);
    
    //Predicate 델리게이트 + 람다
    Predicate<int> calculator3 = (a) => a > 5;
    Console.WriteLine(calculator3(20));
}

 

출력

Comments