C#의 델리게이트는 특정 매개변수 형식과 반환 타입을 가진 메서드를 참조하는 데 사용되는 특수한 형식입니다. 이를 통해 메서드를 변수처럼 다룰 수 있으며, 다른 메서드에 전달하거나 동적으로 호출할 수 있습니다. 델리게이트는 이벤트 기반 프로그래밍의 핵심 요소로, 예를 들어 사용자 인터페이스에서 버튼 클릭과 같은 이벤트 발생 시 특정 작업을 수행하도록 설계된 메서드를 연결하는 데 유용합니다.
다음은 간단한 델리게이트 선언 예제입니다:
public delegate double MathOperation(double a, double b);
이 델리게이트는 두 개의 double 값을 받아 double 값을 반환하는 모든 메서드와 호환됩니다. 이를 통해 정의된 메서드를 다양한 상황에서 재사용할 수 있습니다.
예시로, 델리게이트를 사용하여 계산 로직을 외부에서 제어할 수 있습니다:
private double Add(double x, double y) => x + y;
private double Multiply(double x, double y) => x * y;
// 델리게이트 인스턴스 생성 및 메서드 할당
MathOperation operation = Add;
Console.WriteLine(operation(5, 3)); // 출력: 8
operation = Multiply;
Console.WriteLine(operation(5, 3)); // 출력: 15
또한 델리게이트는 익명 메서드 또는 람다 표현식을 통해 더욱 간결하게 사용할 수 있습니다. C# 2.0 이후 도입된 익명 메서드와 3.0부터 등장한 람다 표현식은 코드의 가독성과 유지보수성을 크게 향상시킵니다.
MathOperation calc = (a, b) => a - b;
Console.WriteLine(calc(10, 4)); // 출력: 6
델리게이트는 여러 메서드를 연결할 수도 있으며, 이는 다중 이벤트 처리나 콜백 체인 구현에 유용합니다. 또한, 메서드 오버로딩 시 반환 타입이 포함된 서명을 고려해야 함에 주의해야 합니다. 즉, 델리게이트와 대응하는 메서드는 정확히 동일한 반환 타입과 매개변수 목록을 가져야 합니다.
다음은 실제 윈도우즈 애플리케이션에서 스레드 내부에서 입력을 비동기로 처리하는 예시입니다. 여기서 ThreadStart를 통해 델리게이트를 사용하여 별도 스레드에서 BeginInput 메서드를 실행하고, 키보드 입력을 감지하여 적절한 처리를 수행합니다:
private void BoardWindow_Loaded(object sender, RoutedEventArgs e)
{
Thread inputMonitor = new Thread(new ThreadStart(() => BeginInput()));
inputMonitor.Start();
}
private void BeginInput()
{
while (true)
{
byte[] keyData = new byte[2];
int result = NewAPI.ScoutKeyPress(keyData);
if (result == 0 && keyData[1] != 0)
{
string keyCode = System.Text.Encoding.Default.GetString(keyData);
ProcessKeyInput(keyCode);
}
else
{
// 오류 로깅 또는 재시도
}
}
}
private void ProcessKeyInput(string code)
{
string action = "";
switch (code)
{
case "31": action = "1"; break;
case "32": action = "2"; break;
case "33": action = "3"; break;
case "34": action = "4"; break;
case "35": action = "5"; break;
case "36": action = "6"; break;
case "37": action = "7"; break;
case "38": action = "8"; break;
case "39": action = "9"; break;
case "30": action = "0"; break;
case "1B": action = "cancel"; break;
case "08": action = "remove"; break;
case "0D": action = "ok"; break;
case "2E": action = "."; break;
default: return;
}
switch (action)
{
case "ok":
Keyselect();
break;
case "cancel":
KeyCancel();
break;
case "remove":
UpdateInputText(text => text.Length > 0 ? text.Substring(0, text.Length - 1) : "");
break;
default:
UpdateInputText(text => text + action);
break;
}
}
private void UpdateInputText(Func<string, string> updater)
{
this.mathKeyBoard1.input.Dispatcher.Invoke(new Action(() =>
{
string current = this.mathKeyBoard1.input.Text;
this.mathKeyBoard1.input.Text = updater(current);
}));
}
이처럼 델리게이트는 메서드의 참조를 추상화함으로써, 코드의 유연성과 확장성을 제공하며, 특히 비동기 처리, 이벤트 리스닝, 알고리즘 컨텍스트 전달 등에서 강력한 역할을 합니다.