델리게이트
- Delegate : 위임, 대리자 ---> 자신에게 전달된 Method를 대신 실행함,
- 키워드는 delegate, new 연산자로 인스턴스를 생성함
- return type과 paramter는 대신 처리하는 Method에 종속적임
- 델리게이트의 인스턴스를 호출한다는 것은 ---> “포인터”가 가르키는 Method를 실행한다는 것
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Delegate
{
class Program
{
static void Main(string[] args)
{
DeleageClass dc = new DeleageClass();
dc.TestMethod();
}
}
class DeleageClass
{
// 델리게이트 선언 - paramater, return type은 대신할 놈과 같다
delegate void SimpleDeleage(string para);
// 델리게이트가 대신할 메소드
private void SimpleCallbackMethod(string para)
{
Console.WriteLine(para);
}
// 델리게이트 테스트 메소드
public void TestMethod()
{
SimpleDeleage sd = new SimpleDeleage(SimpleCallbackMethod);
sd("테스트에요");
sd.Invoke("테스트에요");
}
}
}
동기화 vs 비동기화

- BeginInvoke / EndInvoke : 비동기 방식, 내부적으로 쓰레드를 생성
- Invoke : 동기방식, 이 작업이 끝나야 다른 작업을 할 수 있음
멀티캐스트 델리게이트
- 멀티캐스트 델리게이트 : 하나의 delegate 로 여러개의 Method를 실행
- MulticastDelegateClass() : System.Deleage.Combine으로 Method들을 Chain 으로 “순차적으로” 관리
- MulticastDelegateClass2() : MulticastDelegate.GetInvocationList() 를 사용하여 Chain 목록을 가져와 return 검사할 수도 있음
- MulticastDelegateClass3() : +, –, +=, –= 을 사용하여 관리함 ---> 이벤트에서도 멀티캐스트 델리게이트 개념을 사용함
class MulticastDelegateClass
{
// 델리게이트 선언
delegate void ProgrammingDelegate();
// 델리게이트 메소드 구현 - parameter, return type 이 델리게이트와 같음
private void 분석() { Console.WriteLine("분석"); }
private void 설계() { Console.WriteLine("설계"); }
private void 개발() { Console.WriteLine("개발"); }
private void 테스트() { Console.WriteLine("테스트"); }
// 테스트
public void MulticastDelegateTest()
{
ProgrammingDelegate pd_분석 = new ProgrammingDelegate(분석);
ProgrammingDelegate pd_설계 = new ProgrammingDelegate(설계);
ProgrammingDelegate phase1 = (ProgrammingDelegate)System.Delegate.Combine(pd_분석, pd_설계);
ProgrammingDelegate pd_개발 = new ProgrammingDelegate(개발);
ProgrammingDelegate phase2 = (ProgrammingDelegate)System.Delegate.Combine(phase1, pd_개발);
ProgrammingDelegate pd_테스트 = new ProgrammingDelegate(테스트);
ProgrammingDelegate phase3 = (ProgrammingDelegate)System.Delegate.Combine(phase2, pd_테스트);
phase3();
}
}
class MulticastDelegateClass2
{
// 델리게이트 선언
delegate bool ProgrammingDelegate();
// 델리게이트 메소드 구현 - parameter, return type 이 델리게이트와 같음
private bool 분석() { Console.WriteLine("분석"); return true; }
private bool 설계() { Console.WriteLine("설계"); return true; }
private bool 개발() { Console.WriteLine("개발 못했어요"); return false; }
private bool 테스트() { Console.WriteLine("테스트"); return true; }
// 테스트
public void MulticastDelegateTest()
{
ProgrammingDelegate pd_분석 = new ProgrammingDelegate(분석);
ProgrammingDelegate pd_설계 = new ProgrammingDelegate(설계);
ProgrammingDelegate phase1 = (ProgrammingDelegate)System.Delegate.Combine(pd_분석, pd_설계);
ProgrammingDelegate pd_개발 = new ProgrammingDelegate(개발);
ProgrammingDelegate phase2 = (ProgrammingDelegate)System.Delegate.Combine(phase1, pd_개발);
ProgrammingDelegate pd_테스트 = new ProgrammingDelegate(테스트);
ProgrammingDelegate phase3 = (ProgrammingDelegate)System.Delegate.Combine(phase2, pd_테스트);
// 요놈은 마지막 "pd_테스트"가 true 를 리턴하므로 항상 ture가 됨
Console.WriteLine(phase3());
Console.WriteLine("-------------------------------------------");
// Delegate List를 통해 return 값을 검사해서 중지하는 예제
System.Delegate[] deleagteList = phase3.GetInvocationList();
bool result = false;
foreach (ProgrammingDelegate prg in deleagteList)
{
result = prg();
if(result == false)
{
Console.WriteLine("{0} 단계에서 실패하여 중단합니다.", prg.Method.Name);
break;
}
}
Console.WriteLine("-------------------------------------------");
}
}
class MulticastDelegateClass3
{
// 델리게이트 선언
delegate bool ProgrammingDelegate();
// 델리게이트 메소드 구현 - parameter, return type 이 델리게이트와 같음
private bool 분석() { Console.WriteLine("분석"); return true; }
private bool 설계() { Console.WriteLine("설계"); return true; }
private bool 개발() { Console.WriteLine("개발 못했어요"); return false; }
private bool 테스트() { Console.WriteLine("테스트"); return true; }
// 테스트
public void MulticastDelegateTest()
{
ProgrammingDelegate pd_분석 = new ProgrammingDelegate(분석);
ProgrammingDelegate pd_설계 = new ProgrammingDelegate(설계);
ProgrammingDelegate pd_개발 = new ProgrammingDelegate(개발);
ProgrammingDelegate pd_테스트 = new ProgrammingDelegate(테스트);
ProgrammingDelegate pd_프로젝트 = new ProgrammingDelegate(pd_분석);
pd_프로젝트 += pd_설계;
pd_프로젝트 += pd_개발 + pd_테스트;
pd_프로젝트 += pd_테스트;
pd_프로젝트 -= pd_테스트;
pd_프로젝트();
Console.WriteLine("-------------------------------------------");
}
}
델리게이트 비동기 호출
- IAsyncResult 인터페이스를 사용하여 비동기 호출을 하고 모니터링함.
class AsyncDelegateClass
{
// 델리게이트 선언
delegate void AsyncDelegate(out int threadID);
// 델리게이트 메소드 구현
private void CallByAsyncDelegateMethod(out int threadID)
{
// IAsyncResult는 비동기 실행을 모니터함
// IAysncResult의 IsComplete를 시험하기 위해 일부러 지연
System.Threading.Thread.Sleep(1);
// out 키워드는 참조로 전달됨을 의미
// ref와는 달리 out은 초기화가 필요없고, 메소드에서 반드시 값이 할당되어야 함.
threadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("비동기 메소드");
}
// 테스트
public void AsyncDelegateTest()
{
AsyncDelegate ad = new AsyncDelegate(CallByAsyncDelegateMethod);
int currentThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
int asyncThreadID;
// 비동기 호출 시작 & 완료 #1
//Console.WriteLine("비동기 호출 시작");
//IAsyncResult asyncResult = ad.BeginInvoke(out asyncThreadID, null, null);
//ad.EndInvoke(out asyncThreadID, asyncResult);
//Console.WriteLine("비동기 호출 완료");
//Console.WriteLine("메인 쓰레드{0}, 비동기 호출된 쓰레드{1}", currentThreadID, asyncThreadID);
//Console.WriteLine("-------------------------------------------");
// 비동기 호출 시작 & 완료 #2
Console.WriteLine("비동기 호출 시작");
IAsyncResult asyncResult = ad.BeginInvoke(out asyncThreadID, null, null);
while(asyncResult.IsCompleted == false)
{
Console.WriteLine("메소드 안 끝났다. 대기중");
}
Console.WriteLine("메소드 끝났다.");
ad.EndInvoke(out asyncThreadID, asyncResult);
Console.WriteLine("비동기 호출 완료");
Console.WriteLine("메인 쓰레드{0}, 비동기 호출된 쓰레드{1}", currentThreadID, asyncThreadID);
Console.WriteLine("-------------------------------------------");
}
}
콜백 메소드 호출
- Delegate 비동기 호출시 Callback Method 사용가능
- ~후에(Back) 호출하다(Call)
- BeginInvoke 메소드에 Callback Method 실행을 위한 AsyncCallback 델리게이트를 전달
// 콜백 메소드
private void CallbackMethod(IAsyncResult asyncResult)
{
// 콜백 메소드에 전달된 AsyncDelegate 델리게이트
AsyncDelegate ad = (AsyncDelegate)asyncResult.AsyncState;
int callbackThreadID;
// 비동기 호출 완료
ad.EndInvoke(out callbackThreadID, asyncResult);
Console.WriteLine("콜백 메소드 비동기 호출 종료");
}
// 테스트 - 비동기 - 콜백메소드
public void AsyncDelegateTest2()
{
// 델리게이트 인스턴스 생성
AsyncDelegate ad = new AsyncDelegate(CallByAsyncDelegateMethod);
int asyncThreadID;
// 콜백 메소드 비동기 호출
Console.WriteLine("콜백 메소드 비동기 호출 시작");
IAsyncResult ar = ad.BeginInvoke(out asyncThreadID, new AsyncCallback(CallbackMethod), ad);
Console.WriteLine("-------------------------------------------");
}
제네릭을 이용한 델리게이트
// 델리게이트 선언 - paramater, return type은 대신할 놈과 같다 ---> T
delegate void GenericDeleage<T>(T item);
// 델리게이트가 대신할 메소드
private void StringMethod(string para) { Console.WriteLine(para); }
private void IntMethod(int para) { Console.WriteLine(para.ToString()); }
이벤트
- .net의 이벤트 : 델리게이트를 확장한 형태로 사용됨
- += 는 델리게이트 연산자
- 이벤트시 호출되는 메소드는 델리게이트 포인터로 연결됨
// 인스턴스 생성
FileSystemWatcher watcher = new FileSystemWatcher(path);
// 이벤트 등록
watcher.Created += new FileSystemEventHandler(watcher_Created);
// 이벤트 실행되도록 상태값 설정
watcher.EnableRaisingEvents = true;
…
// 이벤트 실행시 실행 메소드
void watcher_Created(object sender, FileSystemEventArgs e)
{
…
}
- FCL(Framework Class Library)에 포함된 System.IO 네임스페이스의 코드는 아래와 같다.
- 이벤트에 사용되는 델리게이트는 공통적으로 object와 EventArgs 클래스를 파라메터로 사용함
namespace System.IO
{
public delegate void FileSystemEventHandler(object sender, FileSystemEventArgs e);
public class FileSystemWatcher : Component, ISupportInitialize
{
public event FileSystemEventHandler Created;
}
}
- 이벤트 제공자 : 자신이 제공할 수 있는 이벤트 공개 (watcher.Created)
- 이벤트 소비자 : 공개된 이벤트를 등록함 (+= new FileSystemEventHandler(watcher_Created); )
- 이벤트 실행 : 이벤트에 해당하는 액션이 발생하면 제공자는 소비자가 등록한 행동을 호출 (watcher_Created를 실행함) ---> 느슨한 연결(Loosey Coupled)


