일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- pintos
- 추상클래스와인터페이스
- 전쟁-전투
- 크래프톤 정글
- 다익스트라
- 파이썬
- anonymous page
- project3
- kraftonjungle
- 백준
- 네트워크
- 크래프톤 정글 4기
- C
- 크래프톤정글
- 유니티
- c#
- 핀토스
- 4기
- 크래프톤정글4기
- User Stack
- 티스토리챌린지
- 알고리즘수업-너비우선탐색2
- 이벤트 함수 실행 순서
- Unity
- 연결리스트
- BFS
- TiL
- 오블완
- KRAFTON JUNGLE
- 알고리즘
- Today
- Total
말감로그
24.08.26 Unity_C# - delegate, event , action 본문
대리자란?
대리자는 매개 변수와 반환 형식이 정해져 있으면, 그 메서드들을 참조할 수 있게 해주는 형식을 말한다.
C#의 대리자의 특징은
- 함수의 포인터가 아닌 대리자 개념을 통해 메서드를 호출한다.
- 동일한 형(매개변수/리턴 타입)을 가진 메서드들을 대리자로 묶어서 관리하고, 한 번에 호출한다.
- 대리자 타입을 통해 함수의 매개 변수로도 전달이 가능하다.
C# 대리자의 종류
delegate
delegate는 특정 메서드를 참조할 수 있는 "포인터" 다. C언어나 C++에서 함수 포인터와 유사한 개념이다.
델리게이트를 사용하면 메서드를 변수처럼 다룰 수있어서, 특정 상황에서 어떤 메서드를 호출할 지 동적으로 결정할 수 있다.
사용할 때는 먼저 델리게이트 형식을 만들고, 그 형식을 객체로 선언한 다음, 메서드와 그 객체를 연결시키는 식으로 해야 한다.
함수 여러개를 동시에 실행시키고 싶을 때 delegate를 쓴다.
delegate의 장점은 복잡한 코드와 복잡한 함수의 연결을 좀 더 간단하게 처리할 수 있다.
// 반환형이 void이고 파라미터가 없는 메서드를 가리킬 수 있는 델리게이트 정의
public delegate void ActionDelegate();
public class Player : MonoBehaviour
{
public ActionDelegate onAction; // 델리게이트 타입의 변수
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
onAction?.Invoke(); // onAction이 설정되어 있다면 호출
}
}
}
Event
이벤트는 주로 어떤 일이 발생했을 때 그에 반응하는 여러 메서드를 호출할 때 사용된다.
이벤트는 델리게이트를 기반으로 하며, "발생자(버튼)" 와 "구독자(UI업데이트, 사운드 재생 등)" 간의 통신을 가능하게 한다.
플레이어가 데미지를 입었을 때 이를 다른 시스템에 알리는 예제
public class Player : MonoBehaviour
{
public delegate void HealthChangedDelegate(float newHealth);
public event HealthChangedDelegate OnHealthChanged;
private float health = 100f;
void TakeDamage(float damage)
{
health -= damage;
OnHealthChanged?.Invoke(health); // 건강 상태가 바뀌면 이벤트 발생
}
}
public class UIManager : MonoBehaviour
{
public Player player;
void OnEnable()
{
player.OnHealthChanged += UpdateHealthUI; // 이벤트 구독
}
void OnDisable()
{
player.OnHealthChanged -= UpdateHealthUI; // 이벤트 구독 해제
}
void UpdateHealthUI(float newHealth)
{
Debug.Log("Health updated: " + newHealth); // UI 갱신
}
}
delegate와 event 의 차이
delegate는 public 한정자로 선언하면 클래스 외부에서 호출이 가능합니다. 클래스 외부에서도 델리게이트에 저장된 메서드를 호출하거나 덮어쓸 수 있음을 의미합니다.
event는 public 한정자로 선언해도 클래스 외부에서 호출이 불가능합니다. 오직 그 이벤트를 정의한 클래스 내부에서만 호출 가능.
외부에서는 이벤트를 구독("+=") 하거나 구독 해제("-=")만 할 수 있습니다.
event는 객체 상태 변화나 사건 발생을 알리는 용도로 사용되고 delegate는 callback의 용도로 사용됩니다.
왜 이런 차이가 있을까? (Feat.ChatGPT)
1. 캡슐화
델리게이트는 외부에서 직접 접근 가능한 메서드 포인터와 같습니다. 외부에서 이를 자유롭게 호출하고 수정할 수 있습니다. 하지만 이렇게 하면 프로그램이 예상하지 못한 방식으로 동작할 수 있습니다.
이벤트는 델리게이트에 대한 외부 접근을 제한함으로써, 클래스 내부에서만 그 이벤트를 발생시킬 수 있도록 합니다. 이는 캡슐화의 원칙을 따르는 것입니다. 클래스 외부에서 내부의 상태나 동작을 통제하지 못하도록 하기 위함입니다.
2. 안정성
이벤트를 통해 특정 상황에서만 메서드를 호출하도록 하여 프로그램의 안정성을 보장할 수 있습니다. 외부에서 무분별하게 이벤트를 호출할 수 없기 때문에, 이벤트를 발생시키는 로직이 클래스 내부에만 존재하게 됩니다.
반면, 델리게이트는 외부에서 무분별하게 호출될 수 있으므로, 이를 사용하는 프로그램이 예상치 못한 방식으로 작동할 위험이 있습니다.
3. 명확한 의도
델리게이트는 콜백을 설정하거나, 메서드를 다른 메서드로 전달할 때 사용됩니다.
이벤트는 클래스의 특정 상황(버튼 클릭, 상태 변경 등)에서만 발생하도록 설계된 동작입니다. 외부에서는 그 상황에 반응할 수 있지만, 그 상황을 직접 발생시키지는 못합니다. 이는 코드의 의도를 명확하게 하고, 이벤트를 언제, 왜 발생시켜야 하는지에 대한 제어를 클래스 내부에서만 가능하도록 합니다.
결론
Delegate : 외부에서 직접 호출할 수 있어 유연하지만, 외부에서의 통제가 가능하기 때문에 잘못 사용될 경우 프로그램이 예기치 않게 동작할 위험이 있습니다.
Event : 클래스 내부에서만 호출할 수 있기 때문에, 외부에서 해당 이벤트를 발생시키는 상황을 통제할 수 있습니다. 이는 프로그램의 안정성과 코드의 명확성을 보장하기 위한 중요한 메커니즘입니다.
Action
C#에서 기본 제공하는 델리게이트 타입으로, 메서드의 반환형이 'void'일때 사용된다.
파라미터가 없는 Action도 있고, 최대 16개까지의 파라미터를 받을 수 있는 Action이 있다.
Action, Func, Event 차이
Action : Action은 매개변수를 받지만 반환값이 없는 델리게이트입니다. 보통 void 형식의 메서드나 함수를 참조하는 데 사용됩니다.
Func : Func는 매개변수를 받고 반환값이 있는 델리게이트입니다. Func는 마지막 매개변수가 반환값인 형식으로 사용됩니다. Func<int,string>은 정수형 매개변수를 받아 문자열을 반환하는 메서드를 참조합니다.
Event : Event는 클래스 내에서 발생한 액션을 구독하고 반응할 수 있는 기능입니다. 이벤트는 특정 상황이나 조건에 따라 호출되는 메서드를 참조하고, 다른 클래스에서 이를 구독하거나 구독 해지하여 이벤트가 발생했을 때 일정한 동작을 수행할 수 있습니다.
null 조건부 연산자 (?.)
델리게이트나 이벤트를 다루다보면 null인지 체크를 해줘야 합니다.
만약 null인 델리게이트를 호출한다면 NullReferenceException이 발생하게 됩니다.
?. 연산자는 ? 왼쪽의 항이 null이 아니라면 . 뒷부분을 실행하겠다는 의미의 연산자입니다.
OnHealthChanged?.Invoke(health);
함수의 경우 Invoke를 붙여서 호출할 수 있게 됩니다. 그리고 이 연산자의 경우 원자적으로 수행이 되는 연산자라서 이 연산 도중 다른 스레드가 개입할 여지가 없어 멀티 스레드 환경에서도 안전하게 돌아가게 됩니다.
"원자적으로 수행된다" 는 말은 어떤 작업이 더 이상 쪼개 수 없는 단일한 작업으로 수행된다는 의미입니다. 즉, 그 작업이 시작되면 도중에 끊기거나 중단되지 않고 완전히 끝날 때까지 다른 작업이 끼어들 수 없는 상태를 말합니다.
'TIL' 카테고리의 다른 글
24.08.28 알고리즘 - 파이썬 내장 함수 (0) | 2024.08.28 |
---|---|
24.08.27 Unity_C# - 동기 비동기(코루틴, async/await, Task.Run()) (1) | 2024.08.27 |
24.08.22 Unity_C# - C#와 C++의 차이, 구조체와 클래스, 박싱과 언박싱, 제네릭 (0) | 2024.08.22 |
24.08.21 Unity_C# - 추상 클래스와 인터페이스 ,virtual (0) | 2024.08.21 |
24.08.20 Unity_C# - 객체 지향 프로그래밍, SOLID 원칙 (0) | 2024.08.20 |