대리자 delegate
대리자란 함수의 호출을 대신하는 객체로 C++의 function 혹은 임의의 함수를 타입지정하는 것과 유사하다.
한정자 delegate 반환 형식 대리자_이름(매개변수_목록)
delegate int MyDelegate(int a, int b);
MyDelegate 타입은 두 int 형 매개변수를 받아 int를 반환하는 함수를 의미한다.
대리자를 통한 함수 호출은 다음과 같다.
1) 대리자를 선언한다.
2) 대리자 인스턴스를 만들고 함수를 등록한다.
3) 대리자를 호출한다.
C++과 다르게 대리자의 함수의 경우 멤버 함수와 정적 함수 모두 형식만 맞으면 등록하여 호출할 수 있다는 점이다. C++에서 멤버 함수의 경우 첫번쨰 인자에 인스턴스를 바인딩해야한다.
class Calculator
{
public int Plus(int a, int b)
{
return a + b;
}
public static int Minus(int a, int b)
{
return a - b;
}
}
static void Main(string[] args)
{
Calculator Calc = new Calculator();
MyDelegate Callback;
Callback = new MyDelegate(Calc.Plus); // 멤버 함수의 등록
Console.WriteLine(Callback(3, 4));
Callback = new MyDelegate(Calculator.Minus); // 정적 멤버 함수의 등록
Console.WriteLine(Callback(5, 3));
}
일반화 대리자
T로 일반화된 대리자를 사용할 수 있다. 다음 정렬 함수에서 두 수의 대소 비교를 하는 함수를 대리자로 사용할 수 있다.
delegate int Comparer(int a, int b);
static void BubbleSort(int[] DataSet, Comparer Pred)
{
for(int p = 0; p < DataSet.Length -1; ++p)
{
for(int q = 0; q < DataSet.Length - 1 - p; ++q)
{
// 정렬을 위한 비교 함수의 대리자
if(Pred(DataSet[q], DataSet[q+1]) > 0)
{
int temp = DataSet[q+1];
DataSet[q+1] = DataSet[q];
DataSet[q] = temp;
}
}
}
}
IComparable<T>를 상속하는 T 객체는 항상 CompareTo 메서드를 제공하기 때문에 다음과 같이 일반화 대리자를 서언하여 해당 정렬 함수에 비교 대리자로 등록할 수 있다.
static int AscendCompare<T>(T a, T b) where T : IComparable<T>
{
return a.CompareTo(b);
}
int[] array = { 3, 4, 2, 1, 8, 6, 5 };
Console.WriteLine("Sorting Asceneding...");
BubbleSort(array, new Comparer(AscendCompare));
대리자 체인
대리자 인스턴스는 둘 이상의 콜백 함수를 등록할 수 있다. 대리자를 통해 함수를 호출하면 차례대로 등록된 함수가 호출된다.
delegate void ThereIsAFire(string location);
static void Call119(string location)
{
Console.WriteLine("소방서죠? 불났아어! 주소는 : {0}", location);
}
static void ShotOut(string location)
{
Console.WriteLine("피하세요! {0}에 불이났어요", location);
}
static void Escape(string location)
{
Console.WriteLine("{0}에서 나갑시다.", location);
}
호출 함수의 추가는 +=로 이루어지고 제거는 -=로 이루어진다.
ThereIsAFire Fire = new ThereIsAFire(Call119);
Fire += new ThereIsAFire(ShotOut);
Fire += new ThereIsAFire(Escape);
System.Delegate 형식의 정적 멤버함수 Combine을 이용하여 한번에 대리자 체인을 만들 수 있다.
ThereIsAFire Fire2 = (ThereIsAFire)Delegate.Combine(new ThereIsAFire(Call119),
new ThereIsAFire(ShotOut),
new ThereIsAFire(Escape));
이름없는 메서드를 통한 대리자 등록
람다 함수와 비슷하게 대리자 인스턴스에 인라인된 무명 메서드 선언과 동시에 델리게이트로 선언하여 콜백을 등록할 수 있다.
MyDelegate Func;
Func = delegate (int a, int b) { return a + b; };
이벤트 event
클래스 내 멤버로 대리자 인스턴스를 두고 사용하고자 할 때 이벤트 event 키워드를 사용한다. 이벤트라는 다른 타입의 인스턴스가 존재하는 것이 아니라 해당 대리자는 클래스 내에서 사용할 것이라는 캡슐화의 의미를 지닌다. 이벤트로 선언된 대리자 인스턴스는 클래스 외부에서 호출될 수 없다.
delegate void EventHandler(string message);
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));
}
}
}
해당 대리자의 호출은 반드시 DoSomething을 통해서 이루어지며 다음과 같이 클래스 외부에서 호출되는 것을 금지한다.
MyNotifier notifier3 = new MyNotifier();
notifier3.SomethingHappened += MyHandler;
for(int i = 1; i < 30; ++i)
{
// 이벤트 발생
notifier3.DoSomething(i);
}
// 에러
notifier3.SomethingHappened("Happened");
'C# > C# 기본' 카테고리의 다른 글
[C#] LINQ (0) | 2021.10.18 |
---|---|
[C#] 람다식 (0) | 2021.10.15 |
[C#] Generic 프로그래밍 / 예외 처리 (0) | 2021.10.12 |
[C#] 배열 / 컬렉션 / 인덱서 (0) | 2021.10.11 |
[C#] 프로퍼티 (0) | 2021.10.08 |