델리게이트
델리게이트는 메소드 에 대한 참조이다. 델리게이트에 메소드의 주소를 할당한 후, 델리게이트를 호출하면 델리게이트가 메소드를 호출해준다.
한정자 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로 선언되어있어도 호출 가능하다. 델리게이트에 비해 이벤트는 안전하다고 할 수 있다. 따라서 델리게이트는 델리게이트대로 콜백용도로 사용하고. 이벤트는 이벤트대로 객체의 상태변화나 사건의 발생을 알리는 용도로 구분해서 사용해야한다.
'C#언어 > 뇌자극C#5.0' 카테고리의 다른 글
C# : Chapter - 11 예외 처리하기 (0) | 2018.01.26 |
---|---|
C# : Chapter -10 일반화 프로그래밍 (0) | 2018.01.14 |
C# : Chapter -9 배열 , 컬렉션 , 인덱서 (0) | 2018.01.12 |
C# : Chapter -8 프로퍼티 (0) | 2018.01.08 |
C# : Chapter -7 인터페이스 (0) | 2017.12.16 |