본문 바로가기
TIL

[TIL] C# 대리자(Delegate)란?

by DearGreen 2024. 9. 26.

C#  대리자(Delegate)란?


 

C#의 대리자에 대해 알아보자. 마이크로소프트 사의 C# 공식 문서를 참고해 알아보자.

 

[대리자(Delegate) 란?]

대리자특정 매개 변수 목록 및 반환 형식이 있는 메서드에 대한 참조를 나타내는 형식입니다. 대리자를 인스턴스화하면 모든 메서드가 있는 인스턴스를 호환되는 시그니처 및 반환 형식에 연결할 수 있습니다. 대리자 인스턴스를 통해 메서드를 호출할 수 있습니다.
대리자는 메서드를 다른 메서드에 인수로 전달하는 데 사용됩니다. 이벤트 처리기는 대리자를 통해 호출되는 메서드라고 할 수 있습니다. 사용자 지정 메서드를 만들면 Windows 컨트롤 같은 클래스가 특정 이벤트가 발생했을 때 해당 메서드를 호출할 수 있습니다. 다음 예제에서는 대리자 선언을 보여 줍니다.

출처 : https://learn.microsoft.com/ko-kr/dotnet/csharp/programming-guide/delegates/

 

[대리자를 인스턴스화 한다는 것이 무슨 뜻인가?]

: 대리자는 Class와 같은 '참조 형식' 이다. 즉, 새로 인스턴스를 생성해야 메모리 위에 대리자를 위한 공간을 마련해준다는 뜻이다. 아래 코드를 살펴보자. 대리자 형식의 인스턴스 'MyDelegate' , 메소드 Add / Subtract 에 delAdd와 delSubtract 대리자 인스턴스가 연결되어 Main 함수에서 대리자가 호출되면 함수의 역할을 그대로 하는 것이다!

using System;

// 대리자 선언
public delegate int MyDelegate(int x, int y);

class Program
{
    // 람다식을 사용해 함수 정의
    public static int Add(int a, int b) => a + b;
    public static int Subtract(int a, int b) => a - b;
    public static int Multiply(int a, int b) => a * b;

    static void Main(string[] args)
    {
        MyDelegate delAdd = new MyDelegate(Add);
        MyDelegate delSubtract = new MyDelegate(Subtract);

        // 메서드 호출
        Console.WriteLine($"덧셈 결과: {delAdd(5, 3)}");
        Console.WriteLine($"뺄셈 결과: {delSubtract(5, 3)}");
    }
}

 

[만약 위 코드를 대리자를 사용하지 않고 작성한다면, 어떤 불편함이 있을까?]

: 아래 코드는 대리자를 사용하지 않고 작성한 코드이다. 아래 함수를 보면 각 연산에 대해 조건문을 추가해 요구 연산의 종류를 확인하고 수행하는등, 코드가 길어지고 복잡해지는 불편함을 겪을 수 있다.

 

using System;

class Program
{
    public static int Add(int a, int b) => a + b;
    public static int Subtract(int a, int b) => a - b;
    public static int Multiply(int a, int b) => a * b;

    static void Main(string[] args)
    {
        int operation = 1; // 1: 덧셈, 2: 뺄셈, 3: 곱셈
        int x = 5;
        int y = 3;

        // 조건문을 통해 메서드 호출
        if (operation == 1)
        {
            Console.WriteLine($"덧셈 결과: {Add(x, y)}");
        }
        else if (operation == 2)
        {
            Console.WriteLine($"뺄셈 결과: {Subtract(x, y)}");
        }
        else if (operation == 3)
        {
            Console.WriteLine($"곱셈 결과: {Multiply(x, y)}");
        }
        else
        {
            Console.WriteLine("잘못된 연산입니다.");
        }
    }
}

 

위 코드를 간단한 예이지만, 프로젝트의 규모가 커지는 경우 아래와 같은 어려움을 겪을 수 있다.

 

1. 코드의 유연성 부족

: 각 기능을 직접 호출해야 하므로, 호출할 메서드를 동적으로 변경하기 어렵다. 예를 들어, 특정 상황에서 다른 메서드를 호출해야 할 때 조건문을 추가해야 하며, 이는 코드 수정이 필요하게 만든다. 

 

2. 중복 코드 증가

: 여러 곳에서 비슷한 로직을 반복적으로 사용해야 할 경우, 같은 코드를 여러 번 작성해야 하므로 코드 중복이 발생한다. 이는 유지보수를 어렵게 한다.

 

3. 가독성 저하

: 위 코드처럼 간단한 조건문이나 반복문이 많아지면 코드의 가독성이 떨어진다. 특히, 로직이 복잡해지면 의도를 파악하기 어려워진다.

 

4. 메서드 추가 및 수정의 어려움

: 새로운 기능을 추가하거나 기존 메서드를 수정할 때, 모든 관련 조건문을 찾아 수정해야 하므로 시간이 오래 걸리고 실수할 가능성이 높아진다.

 

대리자를 통해 함수를 매개변수로 전달하는 등의 유연함을 더하는 습관을 더해야겠다.