728x90
반응형
1. 개요
using System;
delegate void HANDLER();
class Button {
public HANDLER handler = null;
public void press() {
handler();
}
}
class Program {
static void Main() {
Button btn = new Button();
btn.press();
}
public static void F1() { Console.WriteLine("F1"); }
public static void F2() { Console.WriteLine("F2"); }
}
위와 같은 코드가 있다고 생각을 해보자.
Button클래스는 실제 GUI에서 사용할 버튼이라고 생각하고
Main에서 Button객체를 만들고 press를 호출하는데
실제 사용할 때는 사용자가 눌러서 실행된다고 생각을 해보자.
그럼 Main에서 btn.handler에 원하는 메소드를 넣어 실행시킬 수 있다.
Delegate Combine으로 여러개의 메소드를 부를 수도 있다.
using System;
delegate void HANDLER();
class Button {
public HANDLER handler = null;
public void press() {
handler();
}
}
class Program {
static void Main() {
Button btn = new Button();
btn.handler = F1;
btn.handler += F2;
btn.press();
}
public static void F1() { Console.WriteLine("F1"); }
public static void F2() { Console.WriteLine("F2"); }
}
그런데 문제가 하나 있다.
handler는 null로 초기화 되어있는데 Main에서 아무런 메소드도 넣지 않는다면
null을 호출해 에러가 날 것이다.
null인지를 판단해야하는데 앞서 작성한 포스팅에 elvis operator가 있다. (https://dhshin94.tistory.com/83)
하지만 handler?(); 로 사용해보면 에러가 난다.
왜냐하면 elvis operator는 ?. 또는 ?[ 의 형태에서만 가능하기 때문이다.
이땐 표현을 좀 바꾸어 handler?.Invoke(); 로 해결 가능하다.
using System;
delegate void HANDLER();
class Button {
public HANDLER handler = null;
public void press() {
// ?. ?[
// handler?(); - error
handler?.Invoke();
}
}
class Program {
static void Main() {
Button btn = new Button();
btn.handler = F1;
btn.handler += F2;
btn.press();
}
public static void F1() { Console.WriteLine("F1"); }
public static void F2() { Console.WriteLine("F2"); }
}
이제 코드의 문제는 사라졌는데 사용자 입장에서 문제가 있다.
해당 버튼에 여러 기능을 구현하려 여러사람이 메소드를 추가하는데
19번째 라인의 btn.handler += F2; 에서 += 을 쓴다는게 =만 썼다고 해보자.
그럼 전에 작성한 F1은 날라가고 F2만 남게된다.
F2를 작성한 사람과 F1을 작성한 사람의 독립성이 없이 연결되어 있어 생기는 문제이다.
이 때 사용하면 되는 것이 event이다.
event를 사용하게 되면 더 이상 =은 사용할 수 없고 오직 +=만 사용할 수 있다.
=를 사용할경우 컴파일러 에러가 난다.
using System;
delegate void HANDLER();
class Button {
public event HANDLER handler = null;
public void press() {
// ?. ?[
// handler?(); - error
handler?.Invoke();
}
}
class Program {
static void Main() {
Button btn = new Button();
btn.handler = F1; // error
btn.handler += F1; // ok
btn.handler += F2; // ok
btn.handler = F2; // error
btn.press();
}
public static void F1() { Console.WriteLine("F1"); }
public static void F2() { Console.WriteLine("F2"); }
}
① event
=> 구독자(Subscriber)의 독립성을 제공하기 위한 도구
=> +=, -= 로만 메소드를 등록할 수 있다.
2. 원리
using System;
delegate void HANDLER();
/*
class Button {
public event HANDLER handler = null;
public void press() {
handler?.Invoke();
}
}
*/
class Button {
private HANDLER handler = null;
public void add_handler(HANDLER f) { handler += f; }
public void remove_handler(HANDELR f) { handler -= f; }
public void press() {
handler?.Invoke();
}
}
class Program {
static void Main() {
Button btn = new Button();
btn.handler = F1; // error
btn.handler += F2; // btn.add_handler(F2);
btn.press();
}
public static void F1() { Console.WriteLine("F1"); }
public static void F2() { Console.WriteLine("F2"); }
}
event의 원리를 파악해보도록 하자.
event를 적으면 컴파일러가 어떤식으로 변경시키는지 간단하게 알아보면 위와 같다.
public필드였던 handler는 private필드로 바뀌게 되고
add_handler와 remove_handler가 생기게 된다.
private이기 때문에 직접 접근 시 에러가 나게 된다.
btn.handler += F1; 과 같이 접근하면 컴파일러가 해당 코드는 btn.add_handler(F1);과 같이 변경 시킨다.
ILDASM으로 event가 있을 때와 없을 때를 비교해보면 아래와 같다.
왼쪽 이미지가 event가 없을 때고, 오른쪽 이미지가 event를 사용했을 때이다.
Button클래스를 보면 handler가 각각 public과 private인 것을 확인할 수 있다.
각각 직접 접근하는 것과 add_handler를 통해 접근하는게 확인된다.
② event의 원리
=> add_handler() / remove_handler() 메소드가 생성
728x90
반응형
'프로그래밍 > C#' 카테고리의 다른 글
[C#] 람다 표현식 (Lambda Expression) (0) | 2020.04.16 |
---|---|
[C#] Action, Func (0) | 2020.04.16 |
[C#] Delegate Chain (0) | 2020.04.07 |
[C#] Delegate Example (0) | 2020.04.06 |
[C#] Delegate (2) (0) | 2020.04.04 |