델리게이트


델리게이트는 메소드 에 대한 참조이다. 델리게이트에 메소드의 주소를 할당한 후, 델리게이트를 호출하면 델리게이트가 메소드를 호출해준다.


한정자 delegate 반환형식 델리게이트이름 ( 매개변수목록 );


델리게이트는 메소드에 대한 참조이기 때문에, 자신이 참조할 메소드의 반환형식과 매개 변수를 명시해줘야 한다.

델리게이트는 인스턴스가 아닌 형식이다. 다시말해 MyDelegate는 int 나 string 같은 형식이며, 메소드를 참조하는 어떠한것을 만들고자 한다면 MyDelegate형식의 인스턴스를 따로 만들어야 한다는것이다.


ex)


delegate int MyDelegate( int a , int b);


int Plus( int a , int b )

{

return a+b;

}


int Minus( int a , int b)

{

return a-b;

// Plus와 Minus 메소드는 모두 MyDelegate 와 같은 반환형식과 매개변수를 가지고 있다.


MyDelegate Callback;


Callback = new MyDelegate( Plus ); // MyDelegate 형식의 Callback 인스턴스가 Plus 메소드를 가르키도록 설정.

Console.WriteLine{ Callback(3,4) ); // 7출력


Callback = new MyDelegate( Minus );

Console.WriteLine( Callback(7,5) ); // 2 출력


델리게이트를 사용하는 언제, 왜 사용하는가?


값이아닌 "코드"를 매개변수로 넘기고싶을때, 델리게이트를 이용할 수 있다.


ex)


//델리게이트 선언

delegate int Compare ( int a , int b );


//Compare 델리게이트가 참조할 비교 메소드 선언

static int AscendComparer( int a , int b );

{

if ( a>b )

return 1;

else if ( a == b)

return 0;

else

reutrn -1;

}


// 정렬할 배열과 비교 메소드를 참조할 델리게이트를 매개변수로 받는 정렬메소드 선언

static void BubbleSort( int[] DataSet , Compare Comparer) // 델리게이트형식 Compare 을 이용해 매개변수로 메소드를 받을 수 있다

{

int i = 0;

int j = 0;

int temp = 0;


for( i =0; i < DataSet.Length-1; i++)

{

for(j=0; j < DataSet.Length- (i+1); j++)

{

if( Comparer( DataSet[j] , DataSet[j+1] ) > 0 )

{

 temp = DataSet[j];

DataSet[j] = DataSet[j+1];

DataSet[j+1] = temp;

}

}

}

}


static void main ( string[] args)

{

int[] array = { 3, 7, 4, 2 ,10 };

BubbleSort ( array , new Compare (AscendCompare) ) ; // AscendCompare 메소드를 델리게이트를 이용해 BubbleSort 메소드에 전달.

...

}


일반화 델리게이트


일반화 메소드를 참조하기위해서는 델리게이트 또한 형식매개변수를 이용하여 선언되어야한다.


ex)


delegate int Compare<T>(T a , T b)

static void BubbleSort<T>( T[] DataSet , Compare<T> Comparer )

{

int i = 0;

int j = 0;

T temp = 0;


for( i =0; i < DataSet.Length-1; i++)

{

for(j=0; j < DataSet.Length- (i+1); j++)

{

if( Comparer( DataSet[j] , DataSet[j+1] ) > 0 )

{

 temp = DataSet[j];

DataSet[j] = DataSet[j+1];

DataSet[j+1] = temp;

}

}

}

}

static int AscendCompare<T>(T a , T b) where T : IComparable<T> // T는 IComparable의 파생클래스이다.

{

return a.CompareTo(b);

}

// int, double. string은 모두 IComparable을 상속해서 Compare()메소드를 구현하고있다.CompareTo() 메소드는 매개변수가 자신보다 크면 -1 , 같으면 0 , 작으면 1 을 반환한다.


델리게이트 체인


델리게이트는 여러개의 메소드를 동시에 참조할 수 있다. 이때 , 메소드들은 델리게이트의 형식에 맞춰야한다. 


ex)


delegate void ThereIsAFire ( string location ) ; 


void call 119( string location )

{

Console.WriteLine("소방서죠? 불이났어요! 주소는{0} 입니다.",location);

}

void ShoutOut ( string location)

{

Console.WriteLine("피하세요! {0}에 불이 났어요!",location);

}

void Escape( string location)

{

Console.WriteLine("{0} 에서 나갑시다!",location);

}


이렇게 선언한 메소드들은 ThereIsAFire 델리게이트가 자신들을 한번에 참조할 수 있게 +=연산자를 이용하여 결합할 수 있다.


ThereIsAFire Fire = new ThereIsAFire( Call119);

Fire += new ThereIsAFire( ShoutOut );

Fire += new ThereisAFire( Escape );


Fire("우리집"); // 소방서죠? 불이났어요! 주소는 우리집입니다. 피하세요 우리집에 불이났어요! 우리집에서 어서 나갑시다! 출력


델리게이트 체인을 만드는 방법


//+=방법은 위에있으므로 생략


//+ 연산자와 = 연산자 사용

ThereIsAFire Fire = new ThereIsAFire( Call119 )

+ new ThereIsAFire( ShoutOut )

+ new ThereIsAFire( Escape );

//-=연산자로 체인제거

Fire -= Fire.Call119; //? 확인필요


//Delegate.Combine() 메소드 사용

ThereIsAFire Fire = (ThereIsAFire) Delegate.Combine

(

new ThereIsAFire( Call119 ),

new ThereIsAFire( ShoutOut ),

new ThereIsAFire( Escape )

); // {}이아닌()임( 매개변수의 개념)


익명 메소드


익명메소드는 델리게이트가 참조할 메소드를 넘겨야 할 일이 생겼는데 , 이 메소드가 두번 다시 사용할 일이 없다고 판단되면, 그때 익명메소드를 사용하면 된다.


익명메소드의 선언


델리게이트 인스턴스 = deleagte(매개변수목록)

{   

// 실행하고자하는 코드

}


ex)


delegate int Calculate ( int a , int b );


Calculate Cal;

Cal = delegate( int a , int b)

{

return a+b;

// 익명메소드 , 따라서 이 메소드는 다시 사용할 수 없다.


//실제 사용방법


BubbleSort(array2, delegate(int a, int b)

{

 if(a<b)

return1;

elseif(a == b)

return 0;

else

return -1;

} ); // 익명메소드 사용


이벤트 : 객체에 일어난 사건 알리기


이벤트의 선언절차


1. 델리게이트를 선언한다 . // 클래스 안에선언해도되고 , 밖에 선언해도된다.

2. 클래스 내에 1에서 선언한 델리게이트의 인스턴스를 event 한정자로 수식해서 선언한다.

3. 이벤트 핸들러를 작성한다. // 이벤트 핸들러는 1에서 선언한 델리게이트와 일치하는 메소드여야한다.

4. 클래스의 인스턴스를 생성하고 이 객체의 이벤트에 3에서 작성한 핸들러를 등록한다.

5. 이벤트가 발생하면 이벤트 핸들러가 호출된다.


step1. 델리게이트를 선언한다.


delegate void EventHandler ( string message);


step2. 클래스 내에 델리게이트의 인스턴스를 event 한정자로 수식해서 선언.


class MyNotifier

{

public event EventHandler SomethingHappened;

public void DoSomething( int number )

{

int temp = number % 10;


if ( temp != 0 && temp%3 ==0)

{

SomethingHappened(String.Format("{0} : 짝" , number) ); // number가 3,6,9가 될때마다 이벤트발생.

}

}

}


step3. 이벤트 핸들러를 작성한다. 


class MainApp

{

static public void MyHandler ( string message) 

// SomethingHappened 이벤트에서 사용할 이벤트핸들러는 EventHandler 델리게이트의 형식과 같아야한다.

{

Console.WriteLine( message );

}

// ..

}


step4.


클래스의 인스턴스를 생성하고 이 객체의 이벤트에 step3에서 작성한 이벤트 핸들러를 등록한다.


class MainApp

{

static public void MyHandler ( string message) 

// SomethingHappened 이벤트에서 사용할 이벤트핸들러는 EventHandler 델리게이트의 형식과 같아야한다.

{

Console.WriteLine( message );

}

static void Main(string[] args)

{

MyNotifier notifier = new MyNotifier();

notifier.SomethingHappened += new EventHandler( MyHandler ); // SomeThingHappened 이벤트에 MyHandler() 메소드를이벤트핸들러로등록.


for ( int i =1; i<30; i++)

notifier.DoSomething(i); // SomethingHappened 이벤트 발생시 MyHandler()이벤트 핸들러 호출.

}

}


step5. 이벤트가 발생하면 이벤트 핸들러가 호출된다.



델리게이트와 이벤트


이벤트는 델리게이트에 event 키워드로 수식해서 선언한 것에 불과하다. 이벤트와 델리게이틀가 가장 크게 다른점은 이벤트는 외부에서 직접사용할 수 없다는 것에 있다. 이벤트는 public 한정자로 선언되어있어도 자신이 선언되어있는 클래스 외부에서는 호출이 불가하다. 반면 델리게이트는 public이나 internal로 선언되어있어도 호출 가능하다. 델리게이트에 비해 이벤트는 안전하다고 할 수 있다. 따라서 델리게이트는 델리게이트대로 콜백용도로 사용하고. 이벤트는 이벤트대로 객체의 상태변화나 사건의 발생을 알리는 용도로 구분해서 사용해야한다.



+ Recent posts