포슀트

C# Delegate (Action, Func, Event)

C# Delegate (Action, Func, Event)

πŸ’« Q


  • λŒ€λ¦¬μž
  • λŒ€λ¦¬μžλ₯Ό μ„ μ–Έν•˜κ³  μ‚¬μš©ν•˜λŠ” 방법
  • λŒ€λ¦¬μžκ°€ μ‚¬μš©λ˜λŠ” μ΄μœ μ™€ 상황
  • μΌλ°˜ν™” λŒ€λ¦¬μžλ₯Ό μž‘μ„±ν•˜κ³  μ‚¬μš©ν•˜λŠ” 방법
  • 읡λͺ… λ©”μ†Œλ“œλ₯Ό μ„ μ–Έν•˜κ³  μ‚¬μš©ν•˜λŠ” 방법
  • 이벀트λ₯Ό μ„ μ–Έν•˜κ³  μ‚¬μš©ν•˜λŠ” 방법

πŸ’« Delegate | λŒ€λ¦¬μž


λ©”μ„œλ“œμ˜ μ°Έμ‘°.
Like ν•¨μˆ˜ 포인터 in C/C++.

λ©”μ„œλ“œλ₯Ό λ³€μˆ˜μ²˜λŸΌ μ“Έ 수 있게 ν•΄μ€€λ‹€ !
λ©”μ„œλ“œλ₯Ό λ³€μˆ˜μ— ν• λ‹Ήν•˜κ³ , λ‹€λ₯Έ λ©”μ„œλ“œμ˜ 인자둜 μ „λ‹¬ν•˜κ±°λ‚˜ λ°˜ν™˜ κ°’μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.

주둜 이벀트 처리, 비동기 처리, 콜백 ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•  λ•Œ μ‚¬μš©λœλ‹€.

🫧 Delegate κ΅¬ν˜„

delegate λ°˜ν™˜νƒ€μž… MyDelegate(λ§€κ°œλ³€μˆ˜); 같은 λͺ¨μ–‘μœΌλ‘œ μ„ μ–Έν•œλ‹€.
λ§€κ°œλ³€μˆ˜λŠ” ν•„μš”ν•œ 만큼 μ„ μ–Έν•  수 μžˆλ‹€. (0 ~ 16개)

주의 !!
delegateλŠ” int, string 같은 ν˜•μ‹(Type)μ΄λ―€λ‘œ,
β€œλ©”μ†Œλ“œλ₯Ό μ°Έμ‘°ν•˜λŠ” κ·Έ 무엇”을 λ§Œλ“€λ €λ©΄ μΈμŠ€ν„΄μŠ€λ₯Ό λ”°λ‘œ λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// μ„ μ–Έ
delegate void MyDelegate(string msg);

// μ •μ˜
void Method1(string msg) => Console.WriteLine(msg);

// μΈμŠ€ν„΄μŠ€ 생성
MyDelegate myDelegate = new MyDelegate(Method1);

// 호좜
myDelegate("Hello, World!");

// Output :
// Hello, World!

🫧 Delegate Why?

β€œκ°’β€μ΄ μ•„λ‹Œ β€œν–‰λ™β€, β€œμ½”λ“œβ€ 자체λ₯Ό μ „λ‹¬ν•˜κ³  싢을 λ•Œκ°€ μžˆλ‹€.

예λ₯Ό λ“€μ–΄ 배열을 μ •λ ¬ν•˜λŠ” λ©”μ„œλ“œλ₯Ό λ§Œλ“€ λ•Œ,
μ˜€λ¦„μ°¨μˆœμœΌλ‘œ 정렬할지, λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ 정렬할지, νŠΉλ³„ν•œ 계산식을 쓸지..

정렬을 μˆ˜ν–‰ν•  λ•Œ μ‚¬μš©ν•˜λŠ” 비ꡐ 루틴을 맀개 λ³€μˆ˜λ‘œ 넣을 수 μžˆλ‹€λ©΄?
이런 고민은 λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” ν”„λ‘œκ·Έλž˜λ¨Έκ°€ μ•Œμ•„μ„œ κ²°μ •ν•  수 μžˆλ‹€.

🫧 Delegate μΌλ°˜ν™”

보톡 λ©”μ†Œλ“œ 뿐만 μ•„λ‹ˆλΌ, μΌλ°˜ν™” λ©”μ„œλ“œλ„ μ°Έμ‘°ν•  수 μžˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// μ„ μ–Έ
// IComparable : 비ꡐ κ°€λŠ₯ν•œ νƒ€μž… (μˆ˜μΉ˜ν˜•, λ¬Έμžμ—΄)
// IComparable.CompareTo() : 비ꡐ λ©”μ„œλ“œ (1, 0, -1)
delegate T MyDelegate<T>(T a, T b) where T : IComparable;

// μ •μ˜
int Add(int a, int b) => a + b;
float Add(float a, float b) => a + b;

// μΈμŠ€ν„΄μŠ€ 생성
MyDelegate<int> myDelegate1 = Add;
MyDelegate<float> myDelegate2 = Add;

// 호좜
int result1 = myDelegate(1, 2);
float result2 = myDelegate(1.0f, 2.0f);

// Output :
// 3
// 3.0

🫧 Delegate 체인

ν•˜λ‚˜μ˜ delegate에 μ—¬λŸ¬ λ©”μ„œλ“œλ₯Ό ν• λ‹Ήν•  수 μžˆλ‹€.
κ·Έλ ‡κ²Œ ν• λ‹Ήν•œ μ—¬λŸ¬ λ©”μ„œλ“œλ₯Ό ν•œλ²ˆμ— ν˜ΈμΆœν•  수 μžˆλ‹€. (λ©€ν‹°μΊμŠ€νŠΈ)

호좜 μˆœμ„œλŠ” ν• λ‹Ήλœ μˆœμ„œλŒ€λ‘œ ν˜ΈμΆœλœλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// μ„ μ–Έ
delegate void MyDelegate(string msg);

// μ •μ˜
void Method1(string msg) => Console.WriteLine(msg);
void Method2(string msg) => Console.WriteLine(msg);

// μΈμŠ€ν„΄μŠ€ 생성
MyDelegate myDelegate;

// 1. ν• λ‹Ή (+=) / ν•΄μ œ (-=)
myDelegate += Method1;
myDelegate += Method2;

// 2. ν• λ‹Ή (+) / ν•΄μ œ (-)
myDelegate = Method1 + Method2;

// 3. ν• λ‹Ή (Delegate.Combine) / ν•΄μ œ (Delegate.Remove)
myDelegate = (MyDelegate) Delegate.Combine(
	new MyDelegate(Method1),
	new MyDelegate(Method2));

// 호좜
myDelegate("Hello, World!");

// Output :
// Hello, World!
// Hello, World!

🫧 Delegate 읡λͺ… λ©”μ†Œλ“œ / 무λͺ… ν•¨μˆ˜ ν™œμš©

읡λͺ… λ©”μ†Œλ“œμ™€ 무λͺ… ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

참고둜 읡λͺ… λ©”μ†Œλ“œλŠ” C# 2.0μ—μ„œ, 무λͺ… ν•¨μˆ˜λŠ” C# 3.0μ—μ„œ λ„μž…λ˜μ—ˆλ‹€.
무λͺ… ν•¨μˆ˜κ°€ νŽΈλ¦¬ν•˜μ§€λ§Œ, ν•˜μœ„ ν˜Έν™˜μ„±μ„ μœ μ§€ν•˜κΈ° μœ„ν•΄ 두 가지 방법을 λͺ¨λ‘ μ§€μ›ν•˜κ³  μžˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// μ„ μ–Έ
delegate void MyDelegate(string msg);

// μΈμŠ€ν„΄μŠ€ 생성
MyDelegate myDelegate;

// 읡λͺ… λ©”μ†Œλ“œ ν• λ‹Ή
myDelegate = delegate (string msg) { Console.WriteLine(msg); };

// 무λͺ… ν•¨μˆ˜ ν• λ‹Ή
myDelegate += (string msg) => { Console.WriteLine(msg); };

// 호좜
myDelegate("Hello, World!");

// Output :
// Hello, World!
// Hello, World!

🫧 Delegate 비동기 처리 (Invoke/BeginInvoke)

Invokeλ‚˜ BeginInvoke, EndInvokeλ₯Ό μ΄μš©ν•΄ 비동기 처리λ₯Ό ν•  수 μžˆλ‹€.
μ“Έ μˆ˜λŠ” μžˆμ§€λ§Œ 였래된 λ°©μ‹μ΄λ―€λ‘œ, 비동기 μ²˜λ¦¬λŠ” Taskλ₯Ό μ“°λŠ” 것이 더 λ°”λžŒμ§ν•˜λ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// https://www.csharpstudy.com/Threads/async-delegate.aspx

// μ„ μ–Έ 및 μΈμŠ€ν„΄μŠ€ 생성
Func<int, int, int> work = GetArea;

// μ •μ˜
int GetArea(int height, int width)
{
	int area = height * width;
	return area;
}

// 비동기 처리
IAsyncResult asyncRes = work.BeginInvoke(10, 20, null, null);
int result = work.EndInvoke(asyncRes);

πŸ’« μΌλ°˜ν™”λœ Delegate


일일이 delegateλ₯Ό μ •μ˜ν•˜λŠ” 것이 λ²ˆκ±°λ‘­λ‹€λ©΄,
Action, Func, Predicate 등을 μ‚¬μš©ν•  수 μžˆλ‹€.

🫧 Action

delegate의 μΌλ°˜ν™”λ‘œ, λ°˜ν™˜ 값이 μ—†λŠ”(void) λ©”μ„œλ“œλ₯Ό μ°Έμ‘°ν•  수 μžˆλŠ” delegate.
λ§€κ°œλ³€μˆ˜λŠ” 0 ~ 16κ°œκΉŒμ§€ μ„ μ–Έν•  수 μžˆλ‹€.

κ·Έ μ΄μƒμ˜ λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜, refλ‚˜ out ν•œμ •μžλ‘œ μˆ˜μ‹λœ 맀개 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 경우라면 직접 λ³„λ„μ˜ λŒ€λ¦¬μžλ₯Ό λ§Œλ“€μ–΄ μ¨μ•Όν•œλ‹€.

1
2
3
4
5
Action<string> myAction = (msg) => Console.WriteLine(msg);
myAction("Hello, World!"); // Hello, World!

Action<int, int> myAction = (a, b) => a + b;
myAction(1, 2); // 3

🫧 Func

delegate의 μΌλ°˜ν™”λ‘œ, λ°˜ν™˜ 값이 μžˆλŠ”(void μ œμ™Έ) λ©”μ„œλ“œλ₯Ό μ°Έμ‘°ν•  수 μžˆλŠ” delegate.
λ§€κ°œλ³€μˆ˜λŠ” 0 ~ 16κ°œκΉŒμ§€ μ„ μ–Έν•  수 있고, λ§ˆμ§€λ§‰ λ§€κ°œλ³€μˆ˜κ°€ λ°˜ν™˜ 값이 λœλ‹€.

κ·Έ μ΄μƒμ˜ λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜, refλ‚˜ out ν•œμ •μžλ‘œ μˆ˜μ‹λœ 맀개 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 경우라면 직접 λ³„λ„μ˜ λŒ€λ¦¬μžλ₯Ό λ§Œλ“€μ–΄ μ¨μ•Όν•œλ‹€.

1
2
Func<int, int, int> myFunc = (a, b) => a + b;
myFunc(1, 2); // 3

🫧 Predicate

Func의 νŠΉμˆ˜ν•œ ν˜•νƒœλ‘œ, λ°˜ν™˜ 값이 bool인 delegate.
ν•˜λ‚˜μ˜ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„ bool 값을 λ°˜ν™˜ν•œλ‹€.

1
2
Predicate<int> myPredicate = (num) => num > 0;
myPredicate(1); // True

πŸ’« Event | 이벀트


이벀트(사건)λ₯Ό κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ λͺ‡ 가지 μ œμ•½μ„ 가진, λž˜ν•‘λœ delegate.

이벀트 | 객체에 μΌμ–΄λ‚œ 사건 μ•Œλ¦¬κΈ°
객체의 μƒνƒœ λ³€ν™”, μ‚¬κ±΄μ˜ λ°œμƒμ„ λ‹€λ₯Έ κ°μ²΄λ‚˜ λ©”μ„œλ“œμ— μ•Œλ¦¬κΈ° μœ„ν•΄ μ‚¬μš©λœλ‹€.
λ‹€λ₯Έ κ°μ²΄λ‚˜ λ©”μ„œλ“œμ—μ„œ 이벀트λ₯Ό κ΅¬λ…ν•˜κ³ , μ΄λ²€νŠΈκ°€ λ°œμƒν•˜λ©΄ μ•Œλ¦Όμ„ λ°›μ•„ μ²˜λ¦¬ν•  수 μžˆλ‹€.

🫧 Eventκ°€ Delegate와 λ‹€λ₯Έ 점

  1. eventλŠ” μ™ΈλΆ€μ—μ„œ 직접 ν˜ΈμΆœν•  수 μ—†λ‹€.
    • delegateλŠ” publicμ΄λ‚˜ internal둜 μˆ˜μ‹λ˜μ–΄ 있으면 κ°€λŠ₯ν•˜λ‹€.
  2. delegateλŠ” interface λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•  수 μžˆμ§€λ§Œ, eventλŠ” interface λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•  수 μ—†λ‹€.
    • eventλŠ” delegate의 μΈμŠ€ν„΄μŠ€μ΄κΈ° λ•Œλ¬Έμ΄λ‹€.

🫧 Event κ΅¬ν˜„

delegateλ₯Ό event ν‚€μ›Œλ“œλ‘œ μˆ˜μ‹ν•΄μ„œ μ„ μ–Έν•œλ‹€.
μ΄λ•Œ μˆ˜μ‹λ˜λŠ” delegateλŠ” 클래슀 밖에 선언해도 되고 μ•ˆμ— 선언해도 λœλ‹€.

eventλŠ” μ„ μ–Έν•œ delegate의 μΈμŠ€ν„΄μŠ€μ΄λ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// delegate μ„ μ–Έ (클래슀 밖에 선언해도 λœλ‹€.)
delegate void MyDelegate(string msg);

// Publisher
class MyClass
{
	// 이벀트 μ„ μ–Έ (MyDelegate의 μΈμŠ€ν„΄μŠ€)
	public event MyDelegate MyEvent;

	// ꡬ독 & ꡬ독 ν•΄μ œ
	public void Subscribe(MyDelegate myDelegate) => MyEvent += myDelegate;
	public void Unsubscribe(MyDelegate myDelegate) => MyEvent -= myDelegate;

	// 이벀트 λ°œμƒ (μ΄λ²€νŠΈλŠ” 클래슀 λ‚΄λΆ€μ—μ„œλ§Œ 호좜 κ°€λŠ₯)
	public void OnEvent(string msg) => MyEvent?.Invoke(msg);
}

// Subscriber
class Program
{
	static void Main()
	{
		MyClass myClass = new MyClass();
		myClass.Subscribe(MyMethod);

		myClass.OnEvent("Hello, World!");

		// μ•„λž˜μ²˜λŸΌ 이벀트λ₯Ό μ™ΈλΆ€μ—μ„œ 직접 호좜 ν•  수 μ—†λ‹€.
		// myClass.MyEvent?.Invoke("Hello, World!");
	}

	static void MyMethod(string msg) => Console.WriteLine(msg);
}
1
2
// Static Event을 μ¨λ³΄λŠ” 것도 κ³ λ €. (특히 Singleton Pattern)
public static event EventHandler MyEvent;
1
2
3
4
5
6
7
8
// κ΅¬λ…ν•˜λŠ” Delegate의 이름은 On + 이벀트 μ΄λ¦„μœΌλ‘œ μ§“λŠ” 것이 κ΄€λ‘€
public void OnMyEvent(string msg) => MyEvent?.Invoke(this, new MyEventArgs(msg));

// 이벀트λ₯Ό λ°œμƒμ‹œν‚€λŠ” λ©”μ„œλ“œλŠ” Raise + 이벀트 μ΄λ¦„μœΌλ‘œ μ§“λŠ” 것이 κ΄€λ‘€
public void RaiseMyEvent(string msg) => OnMyEvent(msg);

// 이벀트 ν•Έλ“€λŸ¬μ˜ 이름은 이벀트 이름 + EventHandler둜 μ§“λŠ” 것이 κ΄€λ‘€
public void MyEventHandler(object sender, MyEventArgs e) => Console.WriteLine(e.Message);

πŸ’« λ©”λͺ¨


  • callback을 κ΅¬ν˜„ν•˜λŠ” 방법.
  • delegateλŠ” μ˜μ–΄λ‘œ β€œλŒ€λ¦¬μΈβ€, β€œμ‚¬μ ˆβ€ μ΄λΌλŠ” 뜻이 μžˆλ‹€.
  • delegateλ₯Ό μ΄μš©ν•΄ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ˜ 일급 κ°μ²΄λ‘œμ„œμ˜ ν•¨μˆ˜ κ°œλ…μ„ κ΅¬ν˜„ν•  수 μžˆλ‹€.
  • delegate (event)λ₯Ό μ΄μš©ν•΄ 이벀트, μ˜΅μ €λ²„ νŒ¨ν„΄μ„ κ΅¬ν˜„ν•  수 μžˆλ‹€.

  • β€˜μ΄κ²ƒμ΄ C#이닀.’, β€˜MSDN’
  • EventEvent-Driven-Programming
  • Lambda-Expression
이 κΈ°μ‚¬λŠ” μ €μž‘κΆŒμžμ˜ CC BY 4.0 λΌμ΄μ„ΌμŠ€λ₯Ό λ”°λ¦…λ‹ˆλ‹€.