Delegate (대리자)

2022. 1. 17. 00:00CSharp/Advance

반응형

특정 매개 변수 목록 및 반환 형식이 있는 메서드에 대한 참조를 나타내는 형식.

 

접근제어자  + delegate + 반환형 + 대리자명 + (전달인수)

public delegate int PerformCalculation(int x, int y);
  • 대리자는 C++ 함수 포인터와 유사하지만 C++ 함수 포인터와 달리 멤버 함수에 대해 완전히 개체 지향
  • 대리자는 개체 인스턴스 및 메서드를 모두 캡슐화합니다.
  • 대리자를 통해 메서드를 매개 변수로 전달
  • 대리자를 사용하여 콜백 메서드를 정의
  • 여러 대리자를 연결할 수 있다. (예를 들어 단일 이벤트에 대해 여러 메서드를 호출할 수 있다)
  • 메서드는 대리자 형식과 정확히 일치하지 않아도 된다. 
    • 대리자 시그니처의 반환 형식에서 파생된 반환 형식이 있는 메서드와 함께 사용하는 방법 (공변성)
      class Mammals {}  
      class Dogs : Mammals {}  
        
      class Program  
      {  
          // Define the delegate.  
          public delegate Mammals HandlerMethod();  
        
          public static Mammals MammalsHandler()  
          {  
              return null;  
          }  
        
          public static Dogs DogsHandler()  
          {  
              return null;  
          }  
        
          static void Test()  
          {  
              HandlerMethod handlerMammals = MammalsHandler;  
        
              // Covariance enables this assignment.  
              HandlerMethod handlerDogs = DogsHandler;  
          }  
      }​
    • 대리자 매개 변수 형식의 기본 형식을 사용하는 매개 변수를 가지고 있는 메서드와 함께 사용하는 방법
      (반공변성 을 이용하여 별도의 여러 처리기 대신 하나의 이벤트 처리기를 사용할 수 있다. )

      // Button.KeyDown 이벤트를 정의하는 KeyEventHandler 대리자. 
      public delegate void KeyEventHandler(object sender, KeyEventArgs e)
      
      // Button.MouseClick 이벤트를 정의하는 MouseEventHandler 대리자.
      public delegate void MouseEventHandler(object sender, MouseEventArgs e)
      
      // EventArgs 매개 변수를 사용하여 이벤트 처리기를 정의하고 
      // 이를 사용하여 Button.KeyDown 및 Button.MouseClick 이벤트를 모두 처리
      // EventArgs는 KeyEventArgs 및 MouseEventArgs의 기본 형식이므로 이 작업을 수행할 수 있다.
      
      // Event handler that accepts a parameter of the EventArgs type.  
      private void MultiHandler(object sender, System.EventArgs e)  
      {  
          label1.Text = System.DateTime.Now.ToString();  
      }  
        
      public Form1()  
      {  
          InitializeComponent();  
        
          // You can use a method that has an EventArgs parameter,  
          // Button.KeyDown 은 EventArgs 를 상속한다. 
          this.button1.KeyDown += this.MultiHandler;  
        
          // You can use the same method
          // Button.MouseClick 또한 EventArgs 를 상속한다. 
          // 그러므로 아래와 같이 사용 가능하다. 
          this.button1.MouseClick += this.MultiHandler;  
        
      }​
  • 람다 식은 인라인 코드 블록을 작성하는 더욱 간단한 방법이다. 특정 컨텍스트에서는 람다 식이 대리자 형식으로 컴파일된다.

예제)

public class Delegates
{
    // Delegate type 선언
    public delegate Shape CreateShapeDelegate();
    public delegate void AddCircleDelegate(Circle e);
    public delegate void AddRectangleDelegate(Rectangle e);
    public delegate void AddTriangleDelegate(Triangle e);

    public interface IShape
    {
        public CreateShapeDelegate CreateShape { get; set; }
    }
    public class Shape
    {
        public Shape() => PrintDraw();
        protected virtual string GetClassName() => GetType().Name;
        protected virtual void PrintDraw() => Console.WriteLine($"Drawing a {GetClassName()}");
    }
    public class Circle : Shape { }
    public class Rectangle : Shape { }
    public class Triangle : Shape { }

    public class Creator
    {
        // call back 용
        public AddCircleDelegate? AddCircleDelegateHandler;
        public AddRectangleDelegate? AddRectangleDelegateHandler;
        public AddTriangleDelegate? AddTriangleDelegateHandler;

        // multi cast
        public CreateShapeDelegate? MultiAction;

        public Shape MakeShape() => new Shape();
        public Circle MakeCircle() => new Circle();
        public Rectangle MakeRectangle() => new Rectangle();
        public Triangle MakeTriangle() => new Triangle();

        public void Test()
        {
            // 공변성 Test
            MultiAction = MakeShape;
            MultiAction += MakeCircle;
            MultiAction += MakeRectangle;
            MultiAction += MakeTriangle;
            MultiAction -= MakeCircle;

            Console.WriteLine("MultiAction test");
            MultiAction();

            Console.WriteLine();
            Console.WriteLine("Message fire test");
            AddCircleDelegateHandler?.Invoke(new Circle());
            AddRectangleDelegateHandler?.Invoke(new Rectangle());
            AddTriangleDelegateHandler?.Invoke(new Triangle());
        }

    }

    public class Test : ITest
    {
        List<Shape> _shapes = new List<Shape>();
        Creator creator = new Creator();
        public CreateShapeDelegate? CallGetShape;

        public void Run()
        {
            //creator.AddCircleDelegateHandler += OnAddCircle;
            //creator.AddRectangleDelegateHandler += OnAddRectangle;
            //creator.AddTriangleDelegateHandler += OnAddTriangle;
            
             // 반공변성 Test (모두 OnAddMultiHandler 에서 처리)
            creator.AddCircleDelegateHandler += OnAddMultiHandler;
            creator.AddRectangleDelegateHandler += OnAddMultiHandler;
            creator.AddTriangleDelegateHandler += OnAddMultiHandler;

            creator.Test();
        }
        public void OnAddCircle(Circle circle)
        {
            Console.WriteLine($"adding {circle.GetType().Name} in List<Shape>");
            _shapes.Add(circle);
            Console.WriteLine($"added {circle.GetType().Name} in List<Shape>");
        }
        public void OnAddRectangle(Rectangle rectangle)
        {
            Console.WriteLine($"adding {rectangle.GetType().Name} in List<Shape>");
            _shapes.Add(rectangle);
            Console.WriteLine($"added {rectangle.GetType().Name} in List<Shape>");
        }
        public void OnAddTriangle(Triangle triangle)
        {
            Console.WriteLine($"adding {triangle.GetType().Name} in List<Shape>");
            _shapes.Add(triangle);
            Console.WriteLine($"added {triangle.GetType().Name} in List<Shape>");
        }

        public void OnAddMultiHandler(Shape shape)
        {
            Console.WriteLine($"adding {shape.GetType().Name} in List<Shape>");
            _shapes.Add(shape);
            Console.WriteLine($"added {shape.GetType().Name} in List<Shape>");
        }

    }
}

 

Add (+=) 

MultiAction += MakeCircle;

 

Remove (-=)

MultiAction -= MakeCircle;

 

관련영상

https://youtu.be/YoXzvghdo9k

 

반응형

'CSharp > Advance' 카테고리의 다른 글

제네릭 컬렉션 (Generic Collection)  (0) 2022.01.24
Record  (0) 2022.01.21
Lambda advanced  (0) 2022.01.20
Action, Func, Lambda  (0) 2022.01.19
Event (이벤트)  (0) 2022.01.18