728x90

함수를 보관하는 통을 만들고(대리자선언) 그 통안에 함수를 넣고

나중에 통을 가져와서 함수를 실행시키는 방식입니다.

void RunB(MyClass c) { ... }

class MyClass
{
    int id;   //필드
    string name;       
    public void Display() { }  //메서드
}

MyClass c = new MyClass();
RunB(c)

Delegate는 위 방법처럼 메서드를 다른 메서드로 전달할 수 있도록 하기 위해 만들어 졌다. 

또한 메서드의 리턴값으로 호출자에게 전달 수도 있다. Delegate를 사용해 보자

 

1. 함수의 매개변수를 delegate로 받아와서 결합도를 낮춘다

namespace DelegateTest
{
    // 대리자를 만들어준다.
    delegate void Del();
    
    // 매개변수가 없고 반환형이 void형인 메서드만 참조 시킬 수 있다.
    
    
    class Mng
    {
        public void Main()
        {
            // myDel이라는 대리자 객체 생성            
            Del myDel;
            
            // Print라는 메서드를 참조해준다.
            myDel = Print;
            
            // 대리자를 이용한 메서드 호출
            myDel();
            
            
            // 메서드를 참조하는 형식은 여러가지를 지원합니다.
            // myDel = new Del(Print);
            // myDel = Print;
            // myDel += Print;
            // -=를 이용하여 뺄 수도 있습니다.
        }

        public void Print()
        {
            Console.WriteLine("대리자를 통한 메서드 호출입니다.");
        }
    }
}

 

 

 

2. 이 통에있는걸 비동기로 실행시킬 수 있다.

BeginInvoke는 delegate와 함께 캡슐화된 예약어입니다.

namespace BeginInvokeTest
{
    delegate void myDelegate();
    class Program
    {
        static void Main(string[] args)
        {
            myDelegate a = Func;

            // a를 어떻게 불러올지 결정해보자
            // 1. a();  # 메서드 호출
            // 2. a.Invoke();  # 메서드 동기적 호출
            // 3.a.BeginInvoke(null, null); # 메서드 비동기적 호출

            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("메인스레드는 이걸 세번 출력해주고 프로그램이 종료될 것이야~");
                Thread.Sleep(100);
            }
        }

        private static void Func()
        {
            // 백그라운드 스레드인지, 스레드풀스레드인지 불 형식으로 출력
            Console.WriteLine(Thread.CurrentThread.IsBackground);
            Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);

            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i+1);
                Thread.Sleep(100);
            }
        }
    }
}

 

 

3. 이 통을 Event와 결합시켜서 사용 할 수 있다.

 - Delegate가 Event와 결합하게되면 이벤트가 발생시 구독자들에게 이벤트 발생을 알릴 수 있다.(콜백메서드 호출)

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Teacher a = new Teacher();

            a.Run();
        }
    }

    // 반환형이 없고 매개변수가 int형인 delegate를
    // namespace단에 선언합니다.
    public delegate void MyDel(int score);

    class Teacher
    {
        public void Run()
        {

            // 학생 두명 생성
            Student1 stu1 = new Student1();
            Student2 stu2 = new Student2();

            // 각각의 학생의 Event(Delegate)에 메서드를 구독시킨다. 
            stu1.Stu1Event += GetScore;
            stu2.Stu2Event += GetScore;


            stu1.Run();
            stu2.Run();
        }

        private void GetScore(int score)
        {
            Console.WriteLine(string.Format("당신의 점수는 {0}점 입니다.", score));
        }
    }


    class Student1
    {
        // 네임스페이스 단에 선언된 Mydel을 이벤트형식으로 선언
        public event MyDel Stu1Event;

        public void Run()
        {
            // 콜백메서드 호출
            Stu1Event(80);
        }
    }

    class Student2
    {
        // 네임스페이스 단에 선언된 Mydel을 이벤트형식으로 선언
        public event MyDel Stu2Event;

        public void Run()
        {
            // 콜백메서드 호출
            Stu2Event(100);
        }
    }
}

 

 

728x90

+ Recent posts