나의 브을로오그으

delegate에 대해서 알아보자. [C#] 본문

c#/c#기본 문법

delegate에 대해서 알아보자. [C#]

__jhp_+ 2022. 1. 11. 20:26

c# 델리게이트란 무엇일까?

 

c# 문법책을 보면은 대부분의 공통적인 문법들은 쉽게쉽게 이해가 되는데

저는 항상 이부분이 조금 이해가 안되었다.ㅎㅎㅎ

아마 비슷한 예제나 실제 코딩을 하면서 써본적이 별로 없으니 그런것 같다.

그런 의미에서 블로그에 글을 남겨보려고 한다.

 

델리게이트는 c/c++개발자에게는 델리게이트를 간단하게 함수 포인터라고 설명한다.

변수에 값을 담는게아니라 이번에는 메소드를 담는 것이다.!!

 

그리고 delegate는 대리자라는 뜻이다.

즉, 우리가 호출 할 메소드를 대신 호출해주는 대리자인 셈이다.

 

문법은 다음과 같다.

접근제한자 delegate 대상_메서드의_반환타입_식별자(..... 대상_메서드의_매개변수_목록.....);

 

 

    public class Disk
    {
        public int CleanDisk(object arg)
        {
            Console.WriteLine("작업 실행");
            return 0;
        }
    }
    public delegate int CleanDiskDelegate(object arg);

    public class Program
    {
        public static void Main(String[] args)
        {
            // 일반적으로 메소드 호출 시 
            Disk disk = new Disk();
            disk.CleanDisk(0);

            // 델리게이트 객체 생성 후 호출
            CleanDiskDelegate cleanFunc = new CleanDiskDelegate(disk.CleanDisk);
            cleanFunc(0);

            // 델리게이트 변수에 new 연산자 없이 값을 할당 할 수 있다.
            CleanDiskDelegate workFunc = disk.CleanDisk;
            workFunc(0);

        }
    }

보면 Disk클래스의 clean작업 자체(메소드)를 등록(변수에 할당)하여 사용하는 것 같다.

 

C#2.0부터는 일반적인 값을 할당하듯이 쓸 수 있어서 편의성이 개선된것 같다.

C#9.0부터는 더욱 강력한 함수 포인터를 지원한다고 한다. 이부분은 다음에 다루어 보겠다.

 

 

 

간단한 산술 연산을 수행하는 델리게이트를 작성해보자.

    public class Mathmatics
    {
        public delegate int CalcDelegate(int x, int y);

        static int Add(int x, int y) {  return x + y; }
        static int Substract(int x, int y) { return x - y; }
        static int Multiply(int x, int y) { return x * y; }
        static int Divide(int x, int y) { return x / y; }

        CalcDelegate[] methods; // 델리게이트 배열 선언

        public Mathmatics()
        {
            // static 메소드를 가리키는 델리게이트 배열 초기화 (더하기, 빼기, 곱하기, 나누기 메소드 등록)
            methods = new CalcDelegate[] { Mathmatics.Add, Mathmatics.Substract, 
                Mathmatics.Multiply, Mathmatics.Divide };
        }

        // methods 배열에 담긴 델리게이트를 opCode 인자에 따라 호출
        public void Calulate(char opCode, int operand1, int operand2)
        {
            switch(opCode)
            {
                case '+':
                    Console.WriteLine("+: " + methods[0](operand1, operand2));
                    break;
                case '-':
                    Console.WriteLine("-: " + methods[1](operand1, operand2));
                    break;
                case '*':
                    Console.WriteLine("*: " + methods[2](operand1, operand2));
                    break;
                case '/':
                    Console.WriteLine("/: " + methods[3](operand1, operand2));
                    break;
            }
        }
    }

    public class Program
    {
        // 3개의 매개변수를 받고 void를 반환하는 델리게이트 정의
        delegate void WorkDelegate(char opCode, int operand1, int operand2);

        public static void Main(String[] args)
        {
            Mathmatics mathmatics = new Mathmatics();
            WorkDelegate workDelegate = mathmatics.Calulate;

            workDelegate('+', 10, 5);
            workDelegate('-', 10, 5);
            workDelegate('*', 10, 5);
            workDelegate('/', 10, 5);
        }
    }

 

 

methods라는 델리게이트 배열 변수에 산술연산 메소드를 등록하고

Calculate메소드에서 해당 델리게이트를 호출하여 산술연산을 수행하도록 코드를 작성한다.

 

WorkDelegate에 Mathmatics의 Calcuate메소드를 등록하면

인수 3개를 넘기게 되면 Calculate메소드를 대신 호출해준다.

 

여기서 델리게이트는 타입이라는 점이 중요하다고 한다.

변수가 사용될 수 있는 곳이면 델리게이트 또한 사용될 수 있다.

 

위의 예제를 통해서 델리게이트는 다음의 특징을 갖는다고 볼수있다.

1. 메서드의 반환값으로 델리게이트를 사용 할 수 있다.

2. 메서드의 인자로도 델리게이트를 전달 할 수 있다.

3. 클래스의 멤버로 델리게이트를 정의 할 수 있다.

 

그런데 여기서 델리게이트는 일종의 예약어인데 타입으로 쓸 수 있는 이유는 뭘까?

delegate 예약어가 메서드를 가리킬 수 있는 내부 닷넷 타입에 대한 "간편 표기법"이라는 점에 있다.

System.MulticastDelegate 타입은 System.Delegate 타입을 상속받고, 그것은 다시 System.Object를 상속받는다.

결국 System.Object를 상속받기 때문에 변수 타입처럼 쓸 수 있는것이다!!!

 

 

delegate는 연산자 오버로딩도 되어있다.!!

 

 

 

public class Program
    {
        delegate void CalcDelegate(int x, int y);
        
        static void Add(int x, int y) { Console.WriteLine(x + y); }
        static void Subtract(int x, int y) { Console.WriteLine(x - y); }
        static void Multiply(int x, int y) { Console.WriteLine(x * y); }
        static void Divide(int x, int y) { Console.WriteLine(x / y); }

        public static void Main(String[] args)
        {
            // 연산자로 연산
            CalcDelegate calc = Add;
            calc += Subtract;
            calc += Multiply;
            calc += Divide;

            // 위의 코드와 동일한 코드
            CalcDelegate calc2 = new CalcDelegate(Add);
            CalcDelegate subtractCalc = new CalcDelegate(Subtract);
            CalcDelegate multiplyCalc = new CalcDelegate(Multiply);
            CalcDelegate divideCalc = new CalcDelegate(Divide);
            calc2 = CalcDelegate.Combine(calc2, subtractCalc) as CalcDelegate;
            calc2 = CalcDelegate.Combine(calc2, multiplyCalc) as CalcDelegate;
            calc2 = CalcDelegate.Combine(calc2, divideCalc) as CalcDelegate;

            calc(10, 5);
            calc2(10, 5);


            calc -= Subtract; // 등록된 메소드를 해제하는것도 가능하다!
            calc(10, 5);

        }
    }

 

 

결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

출처 : http://www.yes24.com/Product/Goods/97314203

 

시작하세요! C# 9.0 프로그래밍 - YES24

이 책의 목표는 확실하다. 여러분이 프로그램을 만들고자 할 때 사용하게 될 C# 프로그래밍 언어의 기초를 단단하게 다질 수 있게 하는 것이다. 이 책에서는 C# 언어의 최신 버전인 C# 9.0의 문법까

www.yes24.com