[C#]델리게이트

김승태·2025년 4월 1일

C#

목록 보기
12/13

🧠 1. 델리게이트란?

✅ 정의

델리게이트(delegate)는 함수를 참조하는 형식(type)으로, "함수를 변수처럼 다룰 수 있게 해주는 것" 으로, 대리자 라고도 함.
-> 참조 타입(Reference Type)

✅특징

  • 특정 메서드의 시그니처(입력 매개변수와 반환 타입)일치하는 메서드를 참조할 수 있는 타입
  • 대리자는 명명된 메서드무명 메서드와 연결하여 인스턴스화 할 수 있음.
  • 메서드를 매개변수로 전달하거나, 런타임에 호출될 메서드를 동적으로 연결할 때 유용

🔰컴파일 시점 및 런타임 시점 비교

컴파일 시점

대리자의 타입이 정의되고, 대리자가 어떤 형식의 메서드를 가리킬 수 있는지 컴파일러가 검사
-> 시그니처(매개변수, 반환형)가 맞는지만 확인

런타임 시점

실제로 대리자에 메서드를 할당할 때, 그 메서드의 메모리 주소(함수 포인터) 가 저장되며,
런타임에 메서드의 주소객체 인스턴스 정보까지 캡처해서 delegate 인스턴스를 만든다
-> 함수 주소 + (필요시) 인스턴스 참조가 저장


🪜 2. 델리게이트 기본 구조

[접근지정자] delegate [반환형][델리게이트 이름](매개변수 타입 매개변수 이름)
[델리게이트 이름]은 이름+Delegate이런식으로 보통 네이밍을 하나, 굳이 그럴 필요는 없음.
선언 위치는 namespace에 자유롭게 위치 가능.

다음 예제를 보며 간단하게 구조를 알아보자.


delegate int MyDelegate(int a, int b);  // 델리게이트 정의

class Program
{
    static int Add(int x, int y) //MyDelegate의 시그니처와 동일 
    {
        return x + y;
    }

    static int Multiply(int x, int y)//MyDelegate의 시그니처와 동일 
    {
        return x * y;
    }

    static void Main()
    {
        MyDelegate d1 = Add;
        MyDelegate d2 = Multiply;

        Console.WriteLine(d1(3, 4)); // 출력: 7
        Console.WriteLine(d2(3, 4)); // 출력: 12
    }
}

delegate int MyDelegate(int a, int b); 에서 반환형은 int 매개변수는 각 int a, intb 이다. 따라서 선언한 MyDelegate와 시그니처가 동일한 형태의 메서드인 AddMultiply를 참조할 수 있음을 알 수 있다.

다음 2개의 예제를 통해 보다 익숙해져 보자

🔍예제 1.문자열 출력 Delegate

delegate void PrintDelegate(string message);

using System;

delegate void PrintDelegate(string message);  // 반환형 void, 매개변수 string

class Example
{
    static void PrintHello(string msg)
    {
        Console.WriteLine("Hello " + msg);
    }

    static void Main()
    {
        PrintDelegate printer = PrintHello;
        printer("World");  // 출력: Hello World
    }
}

🔍예제 2.배열 Delegate

using System;

delegate void ActionDelegate();

class Example
{
    static void SayA()
    {
        Console.WriteLine("A");
    }

    static void SayB()
    {
        Console.WriteLine("B");
    }

    static void Main()
    {
        ActionDelegate[] actions = new ActionDelegate[2];
        actions[0] = SayA;
        actions[1] = SayB;

        for (int i = 0; i < actions.Length; i++)
        {
            actions[i]();  // 출력: A B
        }
    }
}

⛓️ 3. 델리게이트 체이닝(Delegate Chaining)

✅정의

여러 개의 메서드를 하나의 델리게이트 인스턴스에 연결해서, 한 번에 순서대로 실행되도록 만드는 기능
-> += 연산자를 사용해서 여러 메서드를 연결 시 델리게이트를 호출할 때 모든 메서드가 순서대로 실행

🔍구현 예제

public delegate void Blinker(); //매개변수, 반환값없는 델리게이트 선언

class Light
{
    public static void Green()
    {
        Console.WriteLine("초록불");
    }

    public static void Yellow()
    {
        Console.WriteLine("노란불");
    }

    public static void Red()
    {
        Console.WriteLine("빨간불");
    }
}

class Program
{
    static void Main()
    {
        Blinker blinker = Light.Green;
        blinker += Light.Yellow;
        blinker += Light.Red;

        blinker();

        // 출력 순서:
        // 초록불
        // 노란불
        // 빨간불
        ->순서대로 실행되는 모습
    }
}

blinker() 호출 시 연결된 모든 메서드가 등록된 순서대로(Green -> Yellow -> Red) 호출됨.

🧷내부 동작 방식(Invocation List)

델리게이트는 내부적으로 메서드 목록을 갖고 있음.

  • += 연산자 를 사용 시: 리스트에 추가
  • -= 연산자 를 사용시: 리스트에서 제거
Delegate[] list = blinker.GetInvocationList();

foreach (Delegate d in list)
{
	Console.WriteLine(d.Method.Name); // 메서드 이름 출력
}
//출력 결과:
//Green
//Yellow
//Red

그렇다면 아래는 결과가 어떻게 될까?

 Blinker blinker = Light.Green;
        blinker += Light.Yellow;
        blinker += Light.Red;

        blinker();
        
        blinker -= Light.Green;
        
        Delegate[] list = blinker.GetInvocationList();

        foreach (Delegate d in list)
        {
            Console.WriteLine(d.Method.Name); // 메서드 이름 출력
        }
        
        //출력결과
        // 초록불
		// 노란불
		// 빨간불
		// Yellow
		// Red

blinker(); 호출 전까지는 blinker 내부에 Green메서드가 있기에 문자열이 출력됐지만, 직후 라인에서는 -=연산자를 통해 제거됐기에 출력이 되지 않음을 볼 수 있다.

profile
긍정머신

0개의 댓글