【 델리게이트란 】
델리게이트는 특정 메서드에 대한 참조를 나타내는 타입 안전한 객체입니다. 이는 C#에서 함수 포인터와 유사하게 작동하며, 한 개 이상의 메서드를 호출할 수 있도록 합니다. 델리게이트는 다음과 같은 상황에서 유용하게 사용됩니다.
1. 이벤트와 콜백 메서드 : 델리게이트는 이벤트와 콜백 메서드를 구현하는 기본적인 수단입니다.
2. 메서드 참조 저장 : 메서드의 참조를 저장하고 실행할 수 있게 합니다.
3. 동적 메서드 호출 : 런타임에 메서드를 동적으로 호출할 수 있습니다.
【 델리게이트의 종류 】
델리게이트 유형 | 설명 |
사용자 정의 델리게이트 | 특정 메서드 시그니처를 직접 정의하여 사용. |
Action 델리게이트 | 반환값이 없는 메서드를 참조. |
Func 델리게이트 | 반환값이 있는 메서드를 참조. |
Predicate 델리게이트 | 반환 타입이 bool인 메서드를 참조하여 조건 검사를 수행. |
멀티캐스트 델리게이트 | 여러 메서드를 참조할 수 있는 델리게이트. |
EventHandler 델리게이트 | 이벤트와 함께 사용되는 표준 델리게이트. |
EventHandler<TEventArgs> 델리게이트 | 사용자 정의 이벤트 인자를 받을 수 있는 제네릭 버전의 이벤트 핸들러 델리게이트. |
1. 사용자 정의 델리게이트
사용자가 직접 정의하는 델리게이트로, 특정 메서드 시그니처를 가리킬 수 있습니다.
// 반환값이 없고, string 매개변수를 받는 델리게이트
public delegate void JamesDelegate(string message);
// float 를 반환하고, 두개의 float 매개변수를 받는 델리게이트
public delegate float CalculateJamesWeightDelegate(float before, float after);
2. 'Action' 델리게이트
'Action' 델리게이트는 반환값이 없는 메서드를 참조할 때 사용됩니다. 매개변수의 개수와 타입을 제네릭으로 지정할 수 있습니다.
// 매개변수가 없는 Action
Action action = () => Debug.Log("Hello, James!");
// 하나의 매개변수르 받는 Action
Action<string> greet = (name) => Debug.Log($"Hello, {name}");
// 두 개의 매개변수를 받는 Action
Action<float, float> addWeight = (before, after) => Debug.Log(before + after);
3. 'Func' 델리게이트
'Func' 델리게이트는 반환값이 있는 메서드를 참조할 때 사용됩니다. 마지막 제네릭 매개변수가 반환 타입을 나타내며, 그 이전의 매개변수들은 메서드의 매개변수를 나타냅니다.
// 반환값이 없는 Func
Func<int> getRandomNumber = () => new Random().Next(1, 100);
// 하나의 매개변수를 받고, 반환값이 있는 Func
Func<string, int> getLength = (str) => str.Length;
// 두 개의 매개변수를 받고, 반환값이 있는 Func
Func<int, int, int> multiply = (a, b) => a * b;
4. 'Predicate' 델리게이트
'Predicate' 델리게이트는 특정 조건을 검사하는 메서드를 참조할 때 사용됩니다. 반환 타입은 항상 'bool'이며, 하나의 매개변수를 받습니다.
// 하나의 int 매개변수를 받아 조건을 검사하는 Predicate
Predicate<int> isEven = (n) => n % 2 == 0;
5. 멀티캐스트 델리게이트
멀티캐스트 델리게이트는 여러 개의 메서드를 참조할 수 있습니다. 델리게이트에 '+=' 연산자를 사용하여 메서드를 추가하고, '-=' 연산자로 메서드를 제거할 수 있습니다.
public delegate void Notify(string message);
public class Program
{
public static void Main(string[] args)
{
Notify notify = ShowMessage;
// += 연산자를 사용
notify += LogMessage;
notify?.Invoke("Process Completed.");
// -= 연산자를 사용
notify -= ShowMessage;
notify?.Invoke("Process Completed Again.");
}
public static void ShowMessage(string message)
{
Console.WriteLine("Show: " + message);
}
public static void LogMessage(string message)
{
Console.WriteLine("Log: " + message);
}
}
6. 'EventHandler' 델리게이트
이벤트와 함께 사용되는 표준 델리게이트로, 매개변수가 두 개(object sender, EventArgs e)인 메서드를 참조합니다.
public class Program
{
public static event EventHandler MyEvent;
public static void Main(string[] args)
{
MyEvent += OnMyEvent;
MyEvent?.Invoke(null, EventArgs.Empty);
}
public static void OnMyEvent(object sender, EventArgs e)
{
Console.WriteLine("Event triggered!");
}
}
7. EventHandler<TEventArgs> 델리게이트
일반적인 이벤트 핸들러 델리게이트의 제네릭 버전으로, 사용자 정의 이벤트 인자를 받을 수 있습니다.
public class MyEventArgs : EventArgs
{
public string Message { get; set; }
}
public class Program
{
public static event EventHandler<MyEventArgs> MyEvent;
public static void Main(string[] args)
{
MyEvent += OnMyEvent;
MyEvent?.Invoke(null, new MyEventArgs { Message = "Hello, Event!" });
}
public static void OnMyEvent(object sender, MyEventArgs e)
{
Console.WriteLine(e.Message);
}
}
【 Unity 이벤트와 C# 델리게이트의 차이점 】
특징 | Unity 이벤트 | C# 델리게이트 |
설정 및 관리 | 인스펙터에서 설정 및 관리 가능 | 코드에서 설정 및 관리 |
사용 편의성 | 비프로그래머도 인스펙터를 통해 설정 가능 | 프로그래머가 코드로 설정해야 함 |
성능 | 약간의 오버헤드 존재 | 상대적으로 높은 성능 |
확장성 | Unity의 다른 시스템과 잘 통합됨 | 일반적이고 강력한 기능 제공 |
타입 안전성 | 제네릭을 사용하여 다양한 타입 처리 가능 | 타입 안전성 보장 |
이벤트 핸들러 추가 | 인스펙터 또는 코드에서 AddListener로 추가 | 코드에서 += 연산자로 추가 |
이벤트 핸들러 제거 | 인스펙터 또는 코드에서 RemoveListener로 제거 | 코드에서 -= 연산자로 제거 |
멀티캐스트 지원 | 지원 | 지원 |
주 사용 용도 | Unity 게임 오브젝트 간의 이벤트 처리 | 일반적인 C# 이벤트 처리 |
주요 장점 | 직관적이고 사용하기 쉬움 | 높은 성능과 유연성 제공 |
주요 단점 | 성능 오버헤드 및 인스펙터 의존성 | 설정 및 관리가 코드로만 가능 |
- C# 델리게이트는 더 높은 성능과 유연성을 제공하며, 코드를 통해 직접 제어할 수 있는 강력한 기능을 제공합니다.
- UnityEvent는 인스펙터에서 쉽게 설정하고 관리할 수 있어, 게임 디자이너나 아티스트가 직접 이벤트를 설정할 수 있는 장점이 있습니다.
Unity 이벤트 예시
using UnityEngine;
using UnityEngine.Events;
public class Player : MonoBehaviour
{
public UnityEvent onJamesEat;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Eat();
}
}
void Eat()
{
Debug.Log("James Eat");
onJamesEat?.Invoke();
}
}
public class GameManager : MonoBehaviour
{
public Player player;
void Start()
{
player.onJamesEat.AddListener(OnJamesEat);
}
void OnJamesEat()
{
Debug.Log("Gain Weight!");
}
}
C# 델리게이트 예시
using System;
public class Process
{
public delegate void ProcessCompletedEventHandler(string message);
public event ProcessCompletedEventHandler ProcessCompleted;
public void StartProcess()
{
Console.WriteLine("Process Started.");
OnProcessCompleted("Process Completed.");
}
protected virtual void OnProcessCompleted(string message)
{
ProcessCompleted?.Invoke(message);
}
}
public class Program
{
public static void Main(string[] args)
{
Process process = new Process();
process.ProcessCompleted += ProcessCompletedHandler;
process.StartProcess();
}
public static void ProcessCompletedHandler(string message)
{
Console.WriteLine(message);
}
}
성능 테스트
using System.Diagnostics;
using UnityEngine;
using UnityEngine.Events;
using Debug = UnityEngine.Debug;
public class ComparePerformance : MonoBehaviour
{
// 델리게이트 선언
public delegate void MyDelegate();
public event MyDelegate MyDelegateEvent;
// UnityEvent 선언
public UnityEvent MyUnityEvent = new UnityEvent();
private const int TestIterations = 1000000;
void Start()
{
// 델리게이트에 메서드 등록
MyDelegateEvent += DelegateMethod;
// UnityEvent에 메서드 등록
MyUnityEvent.AddListener(UnityEventMethod);
// 델리게이트 성능 테스트
var delegateStopwatch = Stopwatch.StartNew();
for (int i = 0; i < TestIterations; i++)
{
MyDelegateEvent?.Invoke();
}
delegateStopwatch.Stop();
Debug.Log($"Delegate Time: {delegateStopwatch.ElapsedMilliseconds} ms");
// UnityEvent 성능 테스트
var unityEventStopwatch = Stopwatch.StartNew();
for (int i = 0; i < TestIterations; i++)
{
MyUnityEvent?.Invoke();
}
unityEventStopwatch.Stop();
Debug.Log($"UnityEvent Time: {unityEventStopwatch.ElapsedMilliseconds} ms");
}
void DelegateMethod()
{
// 빈 메서드
}
void UnityEventMethod()
{
// 빈 메서드
}
}
결과
'개발💻 > C#' 카테고리의 다른 글
[C#] Coupling, Cohesion 1 (0) | 2024.08.10 |
---|---|
[C#] Observer Pattern 1 (0) | 2024.07.13 |
[C#] Delegate 2 (0) | 2024.06.24 |
[C#] Using 지시문 (2) | 2022.08.24 |
[C#] Namespace (0) | 2022.08.23 |