반응형
반응형
Delegate[대리자]란?
- 메서드의 대리자
- 메서드를 보다 효율적으로 사용하기 위하여 특정 메서드 자체를 캡슐화 할 수 있게 만들어주는 방법

using System;

namespace DelegateTest
{
delegate void pis1();
delegate void pis2(int x);
class Test1
{
public void x1()
{
Console.WriteLine("Test1");
}
public void x2(int y)
{
Console.WriteLine("Test2 " + y);
}
}

class Test2
{
[STAThread]
public static void Main(string[] args)
{
Test1 t1 = new Test1();
pis1 p1 = new pis1(t1.x1);
pis2 p2 = new pis2(t1.x2);
p1();
p2(100);
}
}
}

============출력결과================
Test1
Test2  100
====================================

이게 Delegate[대리자]이다. 솔직히 -.- 왜 쓰는지 모르겠다. 밑의 소스를 보면 알겠지만

using System;

namespace DelegateTest
{
class Test1
{
public void x1()
{
Console.WriteLine("Test1");
}
public void x2(int y)
{
Console.WriteLine("Test2 " + y);
}
}
class Test2
{
[STAThread]
public static void Main(string[] args)
{
Test1 = new Test1();
t1.p1();
t1.p2(100);
}
}
}

============출력결과================
Test1
Test2  100
====================================

이 소스랑 다른게 몬가? 출력결과는 똑같은데... --;;; 이제 공부해야지...자 찾아보자
소설같은 C#의 5장 Delegate를 보면...간단하게 설명되어 있다. 몬소린지 하나도 모르겠다. 정말..-_-;
나중에 더 자세히 설명해준다는데...것참....

그래서 "vs 2005로 배우는 C#게임프로그래밍" 책을 봐야겠다.
좀 더 자세하게 설명되어 있다.

Delegate[델리게이트, 대리자]
- 대리자라는 사람은 무엇인가의 일을 대신해주는 사람이란 뜻이다. 이와 같이 C#에서는 어떠한 기능을 대신 수행해주는 역할
- Delegate[델리게이트, 대리자]는 사용자 정의형으로 정의할 수 있다.
 사용자 정의형의 대표적인 예는 Class[클래스]이다.

사용자 정의 -- delegate string dele(string Str);     함수(메서드)형태로 정의함
                 -- Class Main{ }
                 -- Class A { }
                 -- Class B { }
위의 그림(?)을 보면 클래스와 같은 위치에서 선언된다. 맨 위의 소스를 보면 이해될 것이다.

delegate void pis1();
delegate void pis2(int x);
class Test1
{
....

보이지? 클래스보다 먼저 선언했다. 같은 위치라는 것... 그리고 함수 형태로 정의한다는 것..리턴형도 있고 말야..+_+ 인자값도 있고
Delegate[델리게이트, 대리자]의 대표적 기능은 메서드를 대신수행하는 역할이란 것이다.
C언어에서는 포인터함수라는 개념이 있다는데 난 C전혀! 모르므로 패스! (-.ㅜ...이러니 내가 미쳐)
예제가 있다. 그런데 위의 예제와 거의 비슷하다. 그래서 또 패스! 할려다가....나에게 좀 필요한 기초가 있어서 만들겠다.

using System;
using System.Collections.Generic;
using System.Text;
namespace DelegateTest
{
//델리게이트 선언
delegate void dele1();
delegate int dele2(int a, int b);
//계산 클래스
class MathClass
{
public void Intro()
{
Console.WriteLine("계산을 시작합니다.");
}
public int Sum(int a, int b)
{
return a+b;
}
}

//프로그램 시작점
class Program
{
static void Main(string[] args)
{
//Math(계산)클래스 선언 및 인스턴스화
MathClass MathClass = new MathClass(); //전에 적은 거 같은데 MathClass MathClass가 클래스 선언
                                                             //new MathClass()가 인스턴스화 시키는 거라고 생각하면 됨
//델리게이트 선언 및 인스턴스화(델리게이트와 클래스는 같은 위치에서 선언된다.)
dele1 Sum1 = new dele1(MathClass.Intro);
dele2 Sum2 = new dele2(MathClass.Sum);
Sum1();
Console.WriteLine("Result : {0}", Sum2(-10, 90));
}
}
}

============출력결과===============
계산을 시작합니다.
Result : 80
===================================

앞의 예제와 거의 비슷하다. -0- 

먼저 MathClass를 만들었다. 이 클래스는 두개의 메서드를 가지고 있다. 하나는 반환형과 매개변수 없는 Intro함수 
하나는 덧셈기능을 수행하여 리턴해주는 Sum함수
자  그럼 먼저 8-9줄에 선언된 Delegate[델리게이트,대리자]를 보면 MathClass가 가지고 있는 함수와 똑같은 형식을 갖춘 Delegate 
두개가 선언되어있다.
dele1은 반환값이나 매개변수가 존재하지 않고 dele2는 두개의 int형 매개변수를 가지고 있으며 int형 반환값을 가지고 있다.

32,33번째 줄을 보면 선언된 델리게이트를 인스턴스화 시켰다. 그리고 생성자에는 메서드가 참조된다.
만약 dele1 Sum1 = new dele1() 이렇게 선언하면 에러가 발생한다. 즉 델리게이트는 반드시 메서드를 참조 시켜야한다는 것!

그리고 만약 dele1에 MathClass.Sum과 같은 매개변수와 선언형식이 다른 메서드를 참조 시키려고 해도 에러가 난다.

한마디로 요약하자면 Delegate 는 연결될 메서드를 반드시 참조시켜야하고 매개변수와 선언형식도 같아야한다는 것이다!

이제까지 Delegate의 기본적인 면만 봤다. 이제 더 고난이도로 접근 -_-; 



Delegate의 연산
- Delegate는 Combine과 Remove라는 두개의 연산메서드를 지원한다. 이말은
 Delegate가 여러 메서드의 참조가 가능하다는 것이다.

Combine : 기존의 위임에 또 다른 위임을 추가합니다.[+] //말을 어렵게 했는데...그냥 추가한다고 보면된다.
Remove : 기존의 위임에 특정 위임을 제거합니다. [-]

using System;
using System.Collections.Generic;
using System.Text;
namespace DelegateTest
{
delegate void deleMath(int Vlue); //델리게이트 선언
class MathClass
{
public int Number;
public void Plus(int Value); //더하기
{
Number += Value; //Number = Number + Value 와 같은 뜻
}
public void Minus(int Value) //빼기
{
Number -= Value; //Number = Number - Value 와 같은 뜻
}
public void Multiply(int Value) //곱하기
{
Number *= Value; //Number = Number * Value 와 같은 뜻
}
}

class Program
{
static void Main(string[] args)
{
//Math 클래스 선언 및 인스턴스화
MatchClass MathClass = new MathClass();
//Delegate 선언 및 인스턴스화(덧셈)
deleMath Math = new deleMath(MathClass.Plus);
//위임 연산(뺄셈, 곱셈 추가)
Math += new deleMath(MathClass.Minus);
Math += new deleMath(MathClass.Multiply);
//결과
MathClass.Number = 10;
Math(10);
Console.WriteLine("Result : {0}", MathClass.Number);
//위임 연산 (뺄셈 제거)
Math -= new deleMath(MathClass.Minus);
//결과
MathClass.Number = 10;
Math(10);
Console.WriteLine("Result : {0}", MathClass.Number);
//위임 연산(곱셈 제거)
Math -= new deleMath(MathClass.Multiply);
//결과
MathClass.Number = 10;
Math(10);
Console.WriteLine("Result : {0}", MathClass.Number);
}
}
}

============출력결과=====================
Result : 100
Result : 200
Result : 20
=========================================

9줄에 정의된 MathClass 메서드들을 살펴보면 3개의 연산 메서드들이 존재한다. 이 메서드들은 매개변수로 받은 값을 Number라는 전역
변수와 연산을 하고 Number변수에 저장된다.

코드 34줄을 보면 Math 델리게이트는 선언과 동시에 Plus메서드를 기본으로 참조 시켰다. 그리고 37, 38줄을 보면 += 연산을 이용하여 추가로
메서드를 추가하고 있다. 이제 Math 델리게이트는 3개의 메서드가 참조된 것이다. 플러스, 마이너스, 곱셈 메서드....

41줄에서 10 이란 매개변수를 넣어 델리게이트를 실행하면 이 델리게이트는 Plus(10), Minus(10), Multiply(10) 이라는 세 개의 
메서드를 차례로 호출하는 것과 같은 의미다.
그래서 결국은 100 이 출력된다.
나머지는 뺄셈 메서드를 빼주면 되고, 나머지는 곱셈 메서드를 빼주면 계산결과가 나온다.


추가 - 내가 위에 클래스랑 같이 Delegate를 선언해야한다고 했는데 ... 꼭 그런건 아닌듯하다.
다음 소스를 보면...
using System;
using System.Text;
namespace DelegateTest
{
class AddFunc
{
static public void Add(int First, int Second)
{
int res = First + Second;
Console.WriteLine("{0}+{1}+{2}", First, Second, res);
Console.ReadLine();
}
}
class MathOp
{
public delegate void Opdelegate(int First, int Second);
public Opdelegate Op;
protected int _first, _second;
public MathOp(int First, int Second)
{
_first = First;
_second = Second;
}
public void Invoke()
{
if (Op != null)
Op(_first, _second);
}
}

class MathDelegateApp
{
static void Main(string[] args)
{
MathOp mo = new MathOp(42, 27);
mo.Op = new MathOp.Opdelegate(AddFunc.Add);
mo.Invoke();
}
}
}
반응형
반응형

책찾아보시면 많이나오죠. 근데 저도 막상 보면 잘모르겟던데요.

그래서 제가 나름데로 개발할때 경험상으로 이해한것을 설명해보겠습니다.

 

 

1. 개념

 만약 어떤 기능을 실행하는 메소드를 호출할 필요가 있을때, 그냥 직접적으로 호출하는 형식입니다.

 델리게이트는 호출하는코드랑 호출되는메서드 사이에 있다고 생각하면 됩니다.

 

어떤 메소드를 호출한다고할때.

델리게이트 사용       : 메소드호출 ---> 델리게이트 ---> 호출당하는 메소드

일반적인메소드호출 : 메소드호출 ---> 호출당하는 메소드

 

즉. 메소트호출쪽은 호출되는메소드를 직접 부르는 것이 아니고 델리게이트를 대신 부르게 됩니다.

 

이처럼 중간자(대리자)역활을 합니다.

 

2. 왜 사용하는지

한마디로 유연성입니다.

저도 첨에책으로만 볼땐 그래서 머! 걍호출하면 되지 웨 써 복잡하게라고 생각했었습니다.

예를들어 폼위에 버튼을 올려놓고 클릭을 하게 되면 클릭이벤트로 가게되죠?

이건 마소에서 처음 .net을 개발할때 버튼콘트롤 소스하고 버튼클릭이벤트메소드(예:button1_Click)

를 델리게이트로 연결했기 때문에 우리가 볼땐 콘트롤을 누르면 이벤트메소드로 가는것처럼 보이는겁니다.

뒤에서는 델리게이트가 중간에 연결을 해주고 있죠!

좀이해가 안가시죠. 그럼 어디에 사용하는지 한번 보죠.

 

3. 어디에 사용하는지

이걸 응용하자면 엄청 많을 것 같은데..

1..한번에 10개의 매소드를 실행하고 싶을때.

    10개의 메소드를 전부 호출하는 것이 아니고.

    델리게이트를 걸어서 델리게이트를 한번호출합니다.

  

2..비동기처리에 사용합니다.

    예를들어 어떤 이벤트가 발생되서 실행되는

    A라는 메소드가 있는데 이놈은 한번 실행하면 최소 10분이상걸리는 놈입니다.]

    보통 델리게이트를 사용하지 않았을 경우 이놈이 끝날때까지 기다린후,다른 처리를 하게되는데.

    델리게이트걸어 비동기화 시켜주게되면 일단 실행이 되고,

    실행이 끝나던말든 다음처리를 할수 있습니다.

    이걸,멀티캐스팅이라고 하나요.

 

  ↓비동기처리의 예  

 using System;

delegate void ShowMessageDelegate(string msg);

class Callable {
  internal void ConcreteShowMessage(string msg) {
    System.Threading.Thread.Sleep(5 * 1000);
    Console.WriteLine(msg);
  }
}

class Caller {
  internal ShowMessageDelegate ShowMessage;

  internal IAsyncResult CallDelegate() {
 
    IAsyncResult ret
        = ShowMessage.BeginInvoke("hello, from delegate!",
            new AsyncCallback(Callback), ShowMessage);
    return ret;
  }

  internal void Callback(IAsyncResult ar) {
    ShowMessageDelegate usedDelegate
        = (ShowMessageDelegate)ar.AsyncState;
    usedDelegate.EndInvoke(ar);
  }
}

class App {
  static void Main() {
    Callable callable = new Callable();
    Caller caller = new Caller();

    caller.ShowMessage
        = new ShowMessageDelegate(callable.ConcreteShowMessage);

    IAsyncResult ar = caller.CallDelegate();

    while(!ar.IsCompleted) {
      System.Threading.Thread.Sleep(500);
      Console.Write(".");
    }
    Console.WriteLine("Done.");
  }
}

소스 설명은 뺐습니다.

[출처] Delegate 사용 2|작성자 니시오카


반응형
반응형

//델리게이트 & 이벤트
//메서드의 대리자
//메서드를 보다 효율적으로 사용하기 위하여 특정 메서드 자체를 캡슐화 할수 있게 만들어 주는 방법
//델리게이트를 사용하려면 어떤 메서드를 호출할 것인지 컴파일할 시점이 아닌 프로그램을 실행하는 런타임 상황에서 결정할 수 있다.

//1단계 - Delegate할 메서드 정의
using System;
class Atype
{
 public void F1() //Delegate 할 Method1
 {
  Console.WriteLine("Atype.F1");
 }
 public void F2(int x) //Delegate 할 Method2
 {
  Console.WriteLine("Atype.F2 =x"+x);
 }
}

//2단계 - Method에 맞는 Delegate 선언
using System;
delegate void SimpleDelegate1(); // Delegate 선언1 --> void F1()
delegate void SimpleDelegate2(); // Delegate 선언2 --> void F2()
class Atype
{
 public void F1() //Delegate 할 Method1
 {
  Console.WriteLine("Atype.F1");
 }
 public void F2(int x) //Delegate 할 Method2
 {
  Console.WriteLine("Atype.F2 =x"+x);
 }
}

//3단계 - 임의의 객체 생성
//Delegate할 Method를 정하고 Delegate를 선언했다면, 이제 Method가 포함된 Class의 객체를 만들어야 한다. 그래야 특정 객체의 메서드가 하나의 독립적인 Delegate로서 활동 할수 있다.
using System;
delegate void SimpleDelegate1(); // Delegate 선언1 --> void F1()
delegate void SimpleDelegate2(int i); // Delegate 선언2 --> void F2()
class Atype
{
 public void F1() //Delegate 할 Method1
 {
  Console.WriteLine("Atype.F1");
 }
 public void F2(int x) //Delegate 할 Method2
 {
  Console.WriteLine("Atype.F2 =x"+x);
 }
}
class DeleTest
{
 public static void Main()
 {
  Atype atype = new Atype(); // 객체(Instance) 생성
 }
}

//4단계 - Delegate 생성과 호출
using System;
delegate void SimpleDelegate1(); // Delegate 선언1 --> void F1()
delegate void SimpleDelegate2(int i); // Delegate 선언2 --> void F2()
class Atype
{
 public void F1() //Delegate 할 Method1
 {
  Console.WriteLine("Atype.F1");
 }
 public void F2(int x) //Delegate 할 Method2
 {
  Console.WriteLine("Atype.F2 =x"+x);
 }
}
class DeleTest
{
 public static void Main()
 {
  Atype atype = new Atype(); // 객체(Instance) 생성
  SimpleDelegate1 s1 = new SimpleDelegate1(atype.F1); //Delegate 생성
  SimpleDelegate2 s2 = new SimpleDelegate2(atype.F2); //Delegate 생성
  
  s1(); //Delegate를 이용한 호출1
  s2(1000); // Delegate를 이용한 호출2
 }
}

 

 


//메소드 호출 : 일반 메소드 & 인스턴스 메소드
using System;

namespace delegateEX
{
 public delegate void MyDelegate(int x); //델리게이트 선언

 class MyClass
 {
  public static void Test(int x)
  {
   Console.WriteLine("Test 메서드의 x 값은 : {0}",x);
  }
  public static void Test2(int x)
  {
   Console.WriteLine("Test2 메서드의 x 값은 : {0}",x);
  }

  class Class1
  {
   [STAThread]
   static void Main(string[] args)
   {
    MyClass.Test(100);  //일반 메소드 호출 형식

    //Test델리게이트 Instance 생성
    MyDelegate MD = new MyDelegate(MyClass.Test);
    MD(100); // 델리게이트를 통한 호출

    MD = new MyDelegate(MyClass.Test2);
    MD(200);
   }
  }
 }
}

 

 

//하나의 Delegate에 여러개의 Delegate등록

using System;
delegate void TopDelegator(string str); //Delegate Declare

class Top
{
 public static void StaticMethod(string str)
 {
  Console.WriteLine("static Method \t");
  Console.WriteLine(str);
 }
 public void NormalMethod(string str)
 {
  Console.WriteLine("Normal Method \t");
  Console.WriteLine(str);
 }
}
class MultiDelegateTest
{
 public static void Main()
 {
  Top t = new Top(); //클래스 인스턴스화
  TopDelegator bank;
  TopDelegator td1 = new TopDelegator(t.NormalMethod); // 델리게이트 인스턴스화
  TopDelegator td2 = new TopDelegator(Top.StaticMethod); // 델리게이트 인스턴스화

  bank = td1;
        bank("add TopDelegator 1"); // 하나의 delegate 호출
  
  
bank += td2;
  bank("add TopDelegator 2"); // 두개의 delegate 호출

  
 
 bank -= td1;
  bank("remove topDelegator 1"); // Delegate 제거
 }
}

 

 

using System;

namespace DelegateEX
{
 public delegate void MyDelegate(string message);//Delegate 선언

 class MyClass
 {
  public string message; //string 변수선언

  public void Process(MyDelegate mydelegate) // 공용 메소드 선언
  {
   mydelegate(message);//선언한 string 변수 삽입
  }
 }

 class Class1
 {
  public static void DisplayMessage1(string message)
  {
   Console.WriteLine("DisplayMessage1 : {0}", message);
  }
  public void DisplayMessage2(string message)
  {
   Console.WriteLine("DisplayMessage2 : {0}",message);
  }

  [STAThread]
  static void Main(string[] args)
  {
   MyClass mc = new MyClass(); // 초기화

 

   mc.message ="cookee";
   MyDelegate md1 = new MyDelegate(DisplayMessage1); 

   mc.Process(md1);

 

   mc.message = "cookee2";
   MyDelegate md2 = new MyDelegate(new Class1().DisplayMessage2);
   mc.Process(md2);

  }
 }
}


 

using System;

namespace DelegateEX
{
 public delegate int MyDelegate(int i, string s);//반환값이 Int, string 매개변수가 두개인 델리게이트 선언.

 class Class1
 {
  public MyDelegate my; //MyDelegate형 my 선언.

  public int Hello(int i,string s) // my가 호출되었을때 실행할 메소드 작성
  {
   Console.WriteLine("Hello MyDelegate my -- {0}",s);
   return i;
  }

  [STAThread]
  static void Main(string[] args)
  {
   Class1 cs = new Class1();//초기화..

   cs.my = new MyDelegate(cs.Hello);//my변수에 처리할 메소드 Hello 할당.
   int i = cs.my(2,"cookee"); // 델리게이트형 변수 my 실행.
   Console.WriteLine(i);
  }
 }
}

using System;

namespace DelegateEX
{
 public delegate void MyDelegate();//void 이고 인자가 없는 delegate 선언.

 class Class1 //서로다른 클래스 : Class1
 {
  public event MyDelegate my; //MyDelegate형 my 선언(my는 이벤트 변수가 된다.) event 키워드 붙인다.

  public void Hello() // my가 실행할 메소드 작성
  {
   Console.WriteLine("다른 클래스에서 인자없고 반환없는 델리게이트 실행한 결과");
  }

  public void TriggerEvent() //이벤트 받는 메소드
  {
   this.my(); //이벤트 메소드 내에서 Event my()실행.
  }
 }

 class execute  //서로다른 메인클래스
 {
  [STAThread]
  static void Main(string[] args)
  {
   Class1 cs = new Class1();//초기화..

   cs.my += new MyDelegate(cs.Hello);//델리게이트변수 my가 처리할 메소드 Hello를 할당.
   cs.TriggerEvent(); //이벤트를 받을 메소드 부름.
  }
 }
}

  Delegate - 7.Event 와 Delegate

//=========================== 1 =========================================================

using System;

namespace DelegateEX
{
 public delegate void MyEventHandler2(string s); //델리게이트 선언

 class myButton2
 {
  public event MyEventHandler2 Event; // delegate형 이벤트 등록.
  
  public void button2_Click(string val)
  {
   Console.WriteLine("{0} : 버튼에서 이벤트 발생 :",val);
  }
  public void button3_Click(string val)
  {
   Console.WriteLine("{0} : 버튼에서 또 이벤트 발생 :",val);
  }
  static void Main(string[] args)
  {
   myButton2 ok = new myButton2();

   //이벤트 발생
   ok.Event += new MyEventHandler2(ok.button2_Click);

   //이벤트 추가
   ok.Event += new MyEventHandler2(ok.button3_Click);
   ok.Event("cookee");
  }
 }
}

 

Delegate - 8. 윈폼띄우기

using System;
using System.Drawing;//솔루션탐색기에서 참조추가 해준다.
using System.Windows.Forms;//마찬가지로 참조추가 해준다.

namespace DelegateEX
{
 public class EventCall
 {
  public static void Hello(object sender, EventArgs e)
  {
   Console.WriteLine("Hello 메소드 실행!!");
  }

  public static void cookee(object sender, EventArgs e)
  {
   int x = 100, y=100;
   Console.WriteLine("cookee");
   Form frm1 = new Form();

   Button btn2 = new Button();
   btn2.Text = "버튼2";

   x = x + btn2.Location.X;
   y = y + btn2.Location.Y;

   btn2.Location = new Point(x,y);
   frm1.Controls.Add(btn2);
   frm1.Show();

   Console.WriteLine("cookee매소드 실행!!");
  }

  public static void Main(string[] args)
  {
   Form f = new Form();

   Button btn = new Button();

   //버튼 속성 지정
   btn.Text = "버튼을 누르면 Hello 메소드실행! ";
   btn.Location = new Point(100,100); // point 구조체의 생성자에 할당.
   btn.Size = new Size(200,30);//size 구조체의 생성자에 할당.
   btn.ForeColor = Color.Black;
   btn.BackColor = Color.Red;

   f.Controls.Add(btn);
   btn.Click += new EventHandler(Hello);

   Button btn1 = new Button();
   btn1.Text = "버튼위에 마우스커서를 올려놓으면 cookee 메소드실행 ";
   btn1.Size = new Size(180,50);
   btn1.BackColor = Color.Yellow;
   btn.Location = new Point(50,100);
   f.Controls.Add(btn1);
   btn1.MouseHover += new EventHandler(cookee);//버튼위에 올려놓으면 새로운 Form이 뜬다.

   Application.Run(f);
  }
 }  
}


 

 

 [출처] Delegate 의 사용|작성자 니시오카  

 

 

 

 

반응형

+ Recent posts

반응형