C#의 Delegate는 간단히 말하면 C++의 함수포인터를 생각하면 된다.
사용방법은 다음과 같다.
'접근제어자' delegate '반환형' 'Delegate명'('파라미터')
using System;
namespace Study22
{
class Program
{
public delegate void FunctionPointer();
static void Print1()
{
Console.WriteLine("Print 1");
}
static void Print2()
{
Console.WriteLine("Print 2");
}
static void Print3()
{
Console.WriteLine("Print 3");
}
static void Print4()
{
Console.WriteLine("Print 4");
}
static void Execute(FunctionPointer fp)
{
fp();
}
static void Main(string[] args)
{
Execute(Print1);
Execute(Print2);
Execute(Print3);
Execute(Print4);
/*
Print 1
Print 2
Print 3
Print 4
*/
}
}
}
using System;
namespace Study22
{
class Program
{
public delegate void FunctionPointer();
static void Print1()
{
Console.WriteLine("Print 1");
}
static void Print2()
{
Console.WriteLine("Print 2");
}
static void Print3()
{
Console.WriteLine("Print 3");
}
static void Print4()
{
Console.WriteLine("Print 4");
}
static void Execute(FunctionPointer fp)
{
fp();
}
static void Main(string[] args)
{
FunctionPointer fp = new FunctionPointer(Print1);
fp += Print2;
fp += Print3;
fp += Print4;
fp();
/*
Print 1
Print 2
Print 3
Print 4
*/
}
}
}
다음과 같이 (+, += , ...) 연산자를 이용해서 한번에 여러가지 메서드를 실행할 수 있게끔 하는 것이 Delegate Chain 이라고 한다.
어떠한 일이 생겼을 때 알려주는 객체가 필요할 때가 있다.
이런 객체를 만들 때 사용하는 것이 바로 이벤트이다.
이벤트의 동작원리는 Delegate와 유사하다.
사용방법은 다음과 같다.
'접근제어자' event 'Delegate명';
delegate와의 차이점은 다음과 같다.
1. 이벤트는 interface 내부에서 선언할 수 있지만, delegate는 선언할 수 없다.
2. 이벤트는 public으로 선언되어 있어도 자신이 선언되어 있는 클래스 외부에서 호출 할 수 없다. 이는 안정성을 추구할 수 있다.
이에 따라 사용 용도가 다음과 같다고 한다.
delegate : CallBack 용도
event : 객체의 상태 변화, 사건의 발생을 알리는 용도
using System;
namespace Study23
{
class Program
{
delegate void EventHandler(string message);
class Notifier
{
public event EventHandler Execute;
public void Notifiy()
{
Random random = new Random();
int r = random.Next(0, 10);
if (r <= 7)
Execute("70% 확률");
}
}
static void Print(string str)
{
Console.WriteLine(str);
}
static void Main(string[] args)
{
Notifier notifier = new Notifier();
// notifier.Execute("");
// CS0070에 의해서 event는 외부에서 호출 불가. 단 += 과 같은 Callback은 가능
notifier.Execute += Print;
notifier.Notifiy();
notifier.Notifiy();
notifier.Notifiy();
}
}
}
매번 Callback 용도로 사용할 함수를 계속해서 생성하면 지저분해지고 굳이 써야할 수 있다. 이를 보완하기 위해서 무명함수와 람다식 방법을 사용하면 편한다.
using System;
namespace study24
{
class Program
{
delegate void DelegateEvent(string msg);
static void Main(string[] args)
{
DelegateEvent de = new DelegateEvent(
(string msg) => { Console.WriteLine("람다 방식 " + msg); }
);
de += delegate (string msg)
{
Console.WriteLine("무명 함수 방식 " + msg);
};
de("execute");
// 람다 방식 execute
// 무명 함수 execute
}
}
}
람다 방식
(파라미터) => { 함수 내용 }
무명함수 방식
delegate(파라미터) { 함수 내용 }
마찬가지로 delegate를 매번 선언하기 귀찮을 수 있다. 이에 따라서 C#에서는 미리 delegate 변수를 정의해놨다.
다음과 같은 조건에 따라서 사용하는 이름이 달라진다.
반환 타입이 없을 경우 : Action
반환 타입이 있을 경우 : Func
보면 다음과 같이 파라미터만큼 제네릭 설정을 할 수 있게끔 되어있다.
이를 통해 delegate 변수를 굳이 여러개 설정하지 않아도 된다.
using System;
namespace Study25
{
class Program
{
static void Main(string[] args)
{
Func<int, int, int> cal =
(int a, int b ) =>
{
return a + b;
};
Console.WriteLine(cal(5, 2));
cal = (int a, int b) =>
{
return a - b;
};
Console.WriteLine(cal(5, 2));
Action<string> action = (string msg) =>
{
Console.WriteLine(msg);
};
action("Action");
/*
* 7
* 3
* Action
*/
}
}
}