[C#] 델리게이트 Delegate

[C#] 델리게이트 Delegate

개요

이번 글에서는 C#에서 중요한 델리게이트(Delegate)에 대해 알아보겠습니다. 델리게이트는 사전적인 의미는 “대리자”, 풀어서 설명하면 “권한을 위임 받아 특정 작업이나 역할을 수행하는 사람 또는 객체”를 뜻합니다. 프로그래밍에서는 특정 작업을 다른 객체에서 대신 작업해준다고 보면 되겠네요. C/C++에서 함수포인터와 비슷하며 함수 포인터보다 대리자는 개체 지향적이고 형식이 안전하며 보안이 유지됩니다.

사실 이렇게 설명만 하면 무슨 말인지 이해되지 않습니다.


기본 사용

아래는 C#에서 델리게이트 선언 방식입니다. 액세스 가능한 클래스 또는 대리자 형식과 일치하는 구조의 모든 메서드는 대리자에 할당할 수 있습니다.

//접근제한자 delegate 반환타입 함수명(매개변수1, 매개변수2, 매개변수3, ...);
public delegate void PrintIntDelegate(int x);

아래와 같이 숫자를 출력하는 함수가 있다면 델리게이트 객체에 참조하여 호출 할 수 있습니다. 델리게이트도 ‘메서드를 참조하는 타입’이므로 델리게이트 선언 이후 객체를 생성하여 함수를 참조할 수 있습니다.

public delegate void PrintIntDelegate(int x);

PrintIntDelegate del1 = new PrintIntDelegate(PrintNo);
del1(10);
del1(15);
del1(20);

public static void PrintNo(int x)
{
    Console.WriteLine("PrintNo: " + x);
}

델리게이트 체인

위와 같이 함수 하나만 사용하는 경우엔 델리게이트를 굳이 사용할 필요는 없습니다. 아래와 같이 동일한 형식의 함수가 3개 있을 때, 델리게이트를 사용하면 한번에 호출 가능합니다.

PrintStringDelegate? del2 = null;
del2 += PrintStr1;
del2 += PrintStr2;
del2 += PrintStr3;
if (del2 != null)
    del2("hi");

del2 -= PrintStr2; // Print2 삭제
Console.WriteLine("--- PrintStr2 제거 ---");
if (del2 != null)
    del2("hi");


public static void PrintStr1(string str)
{
    Console.WriteLine("PrintStr1: " + str);
}

public static void PrintStr2(string str)
{
    Console.WriteLine("PrintStr2 [" + str + "]");
}

public static void PrintStr3(string str)
{
    Console.WriteLine(str + " - PrintStr3");
}

위 코드는 각기 다른 문자열 출력 함수 PrintStr1, 2, 3을 델리게이트에 추가한 뒤 한번에 호출하는 함수 입니다. +=는 델리게이트에 함수를 등록하는 것이며 반대로 -=는 함수를 삭제하는 것입니다.
이렇게 하나의 호출자에 여러 개의 메서드를 등록하는 것을 델리게이트 체인이라고 합니다.


델리게이트와 콜백 함수

델리게이트도 하나의 타입이기에 메서드 매개변수로 전달이 가능합니다. 아래와 같이 델리게이트를 메서드 매개변수로 전달하여 콜백 함수로 호출 할 수 있습니다.

PrintStringDelegate? del3 = null;
del3 += PrintStr1;
del3 += PrintStr2;
DelegateCallback("콜백1", del3);
Console.WriteLine("======================");
PrintStringDelegate? del4 = null;
del4 += PrintStr2;
del4 += PrintStr3;
DelegateCallback("콜백2", del3);
Console.WriteLine("======================");

public static void DelegateCallback(string str, PrintStringDelegate del)
{
    del(str);
}

제네릭 델리게이트

델리게이트는 일반화 메소드도 등록하여 사용 가능합니다. 다만 델리게이트 또한 일반화 되어야 합니다. 델리게이트 일반화는 함수 일반화와 같습니다.

public delegate void GenericDelegate<T>(T type);

아래와 코드는 델리게이트에 일반화 함수를 등록하여 호출 하는 예제입니다.

public delegate void GenericDelegate<T>(T type);

GenericDelegate<int>? del5 = null;
del5 += GenericFunction1;
del5 += GenericFunction2;
del5 += GenericFunction3;
del5(100);
Console.WriteLine("======================");

GenericDelegate<string>? del6 = null;
del6 += GenericFunction1;
del6 += GenericFunction2;
del6 += GenericFunction3;
del6("abcdefg");

public static void GenericFunction1<T>(T type)
{
    Console.WriteLine($"Generic Function1: parameter({type}), parameter type(${type.GetType()})");
}

public static void GenericFunction2<T>(T type)
{
    Console.WriteLine($"Generic Function2 - parameter: {type}, type: ${type.GetType()}");
}

public static void GenericFunction3<T>(T type)
{
    Console.WriteLine($"Generic Function3: parameter, type({type}, ${type.GetType()})");
}

github : https://github.com/3001ssw/c_sharp/tree/main/Delegate