Dlelegate는 컴파일 시점이 아닌 프로그램 구동 시에 실행된다.
메소드를 참조할 수 있는 타입으로, 메소드의 인수로 전달할 수 있다.
메소드와 동일한 시그니처를 가지며, 대리자 인스턴스를 호출하면 대리자에 연결된 메서드가 실행된다.
“delegate” 타입을 선언하면 컴파일러가 자동으로 Delegate 클래스를 상속하는 클래스를 생성해 준다.
(Delegate 클래스는 delegate 타입이 아니며, delegate 타입의 베이스 클래스일 뿐이다)
Delegate 클래스를 상속한 클래스를 만들 수 있는 권한은 시스템과 컴파일러만 갖고 있다. 때문에 Delegate 클래스를 상속한 delegate 타입을 상속하는 새로운 타입을 만들 수 없다.
대리자는 이벤트 처리기와 콜백 메서드 등에 유용하게 사용된다. 예를 들어, 버튼을 클릭했을 때 실행되는 이벤트 처리기는 대리자를 사용하여 구현된다.
또한 비동기 작업을 처리할 때 콜백 메서드를 사용하는데, 대리자를 사용한다.
delegate int AddDelegate(int a, int b);
class CalcDelegate
{
public int Add(int a, int b)
{
return a + b;
}
}
static void Main(string[] args)
{
CalcDelegate calc = new CalcDelegate();
AddDelegate add = new AddDelegate(calc.Add);
int result = add(3, 4);
Console.WriteLine(result);
}
📌c# 2.0에서는 할당하는 식으로 정의를 한다.(버전별로 델리게이트 정의하는 법에 차이가 있다.)
CalcDelegate calc = new CalcDelegate();
AddDelegate add = calc.Add;
하나의 델리게이트가 하나의 메소드를 래핑하지 않고 두 개 이상의 메소드를 래핑하여 호출한다.
주의사항
멀티캐스트 델리게이트를 사용할 때 반드시 델리게이트와 델리게이트가 참조하는 메소드들의 반환형이 void형이어야 한다.
다른 코드 블록에서 재사용될 일이 없는 이름없는 메소드
delegate int Calculate(int a, int b);
public static void Main(){
Calculate calc;
calc = delegate(int a, int b){
return a + b;
};
}
이벤트는 특정 상황, 조건이 발생했을 때 이벤트 핸들러에게 알리는 메커니즘이다. 예를 들어 GUI 요소에서 버튼 클릭, 마우스 이동 등 이벤트가 발생하는
특정 조건이 충족될 때 호출된다.
이벤트를 사용하기 위해서는, 델리게이트가 선제적으로 존재해야 한다.
이벤트를 포함하고 있는 클래스는 호출할 수 있는 멤버 메소드가 있어야 한다.
namespace System
{
//
// 요약:
// Represents the method that will handle an event that has no event data.
//
// 매개 변수:
// sender:
// The source of the event.
//
// e:
// An object that contains no event data.
public delegate void EventHandler(object? sender, EventArgs e);
}
미리 정의되어 있는 EventHandler라는 이름의 delegate
class Program
{
static void Main(string[] args)
{
var button = new MyButton();
// 3. eventhandler에 이벤트 추가
button.Click += new EventHandler(BtnClick);
// 4. 이벤트 발생을 위한 함수 호출
button.MouseButtonDown();
}
// 2. eventhandler에 추가할 형식에 맞는 event 함수 선언
static void BtnClick(object sender, EventArgs e)
{
Console.WriteLine("button clicked!");
}
}
public class MyButton
{
// 1. event 선언
public event EventHandler Click;
public void MouseButtonDown()
{
if (this.Click != null)
{
// 5. 이벤트 발생
Click(this, EventArgs.Empty);
}
}
}
이벤트는 주로 다음과 같은 상황에 사용된다.
1.이벤트 핸들링 : 이벤트는 객체 간의 상호작용에서 중요한 역할을 한다. 이벤트를 사용하여 다른 객체나 사용자의 동작에 대한 알림을 제공하고, 이에 대한 응답으로 특정 동작을 수행한다. 예를 들어, 버튼 클릭, 마우스 이동, 키 입력 등의 동작에 대한 이벤트를 처리하여 UI 상호작용을 구현할 수 있다.
2.이벤트 기반 아키텍처 : 이벤트는 이벤트 기반 아키텍처에서 핵심적인 역할을 수행한다. 이벤트를 사용하여 애플리케이션의 다양한 컴포넌트나 모듈 간의 통신을 단순하고 유연하게 구성할 수 있다. 이벤트를 통해 컴포넌트 간의 결합도를 낮추고 재사용성을 높일 수 있다.
3.이벤트 드리븐 프로그래밍 : 이벤트는 이벤트 드리븐 프로그래밍 패턴에서 핵심적인 요소이다. 이 패턴은 비동기적인 상황에서 이벤트에 의해 트리거 되는 동작을 효과적으로 처리하는 방법을 제공한다. 예를 들어, 네트워크 통신, 사용자 입력, 외부 리소스 접근 등의 비동기 작업을 이벤트에 의해 처리할 수 있다.
람다식(Lambda Expression)은 익명 메소드의 일종으로서 대리자 또는 함수 형식을 대치할 수 있다.
매개변수를 받아 지정된 작업을 수행하는 코드를 짧게 작성할 수 있기 때문에 다양한 상황에서 사용된다.
식 트리 (Expression Tree) 구축에 람다식 사용한다.
이벤트 처리나 LINQ에서 쿼리문, 대리자(Delegate)로 자주 사용된다.
람다식에서 return을 구현하려면 {}을 사용한다.
(parameters) => expression
(parameters) => { statements; }
parameters: 람다 함수의 입력 매개변수를 정의. 매개변수를 받지 않는 경우 빈 괄호 ()로 표시한다. 매개변수 하나만 있는 경우 괄호를 생략할 수 있다.
expression: 람다 함수의 본문을 나타내는 표현식. 이 표현식의 결과가 람다 함수의 반환값이 된다.
statements: 여러 문장이다. 중괄호를 사용해야 하며 return 키워드를 통해 값을 반환할 수 있다.
using System;
class Program
{
// 대리자 정의
delegate int Operation(int x, int y);
static void Main()
{
// 람다 식을 이용해 대리자 인스턴스 생성
Operation add = (a, b) => a + b;
Operation subtract = (a, b) => a - b;
// 대리자 호출
Console.WriteLine("Addition: " + add(10, 5)); // 결과: 15
Console.WriteLine("Subtraction: " + subtract(10, 5)); // 결과: 5
}
}
using System;
class Program
{
// 사용자 정의 대리자
delegate string StringOperation(string input);
static void Main()
{
// 람다 식을 이용한 사용자 정의 대리자 인스턴스 생성
StringOperation reverse = s =>
{
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
};
// 대리자 호출
string result = reverse("hello");
Console.WriteLine("Reversed string: " + result); // 결과: "olleh"
}
}
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> names = new List<string> { "Alice", "Bob", "Charlie", "Dave" };
// Sort 메서드에 람다 식을 직접 전달
names.Sort((a, b) => a.Length.CompareTo(b.Length));
foreach (var name in names)
{
Console.WriteLine(name); // 출력: Bob, Dave, Alice, Charlie
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Where 메서드에 람다 식을 직접 전달
var evenNumbers = numbers.Where(n => n % 2 == 0);
foreach (var num in evenNumbers)
{
Console.WriteLine(num); // 출력: 2, 4, 6, 8, 10
}
}
}
정의 : 익명 메서드와 람다식처럼 델리게이트에 메서드를 담아 전달하는 과정을 간단히하는 역할을 한다.
미리 정의된 델리게이트 변수
Action : 반환값이 없는 델리게이트
선언
매개변수 없음 : Action act;
매개변수 있음 : Action<매개변수 타입> act;
Func : 반환값이 있는 델리게이트
선언 : Func<매개변수 타입, 매개변수 타입, 반환값의 타입> func;
델리게이트 : 델리게이트는 메서드 시그니처(매개변수 타입과 반환 타입)를 나타내며, 델리게이트 인스턴스를 선언하고 초기화할 때에는 기존 메서드의 이름을 지정해야 한다. 즉, 메서드 이름을 사용하여 델리게이트를 생성하고 호출한다.
delegate int MyDelegateFunction(int x, int y);
MyDelegateFunction add = AddNumbers; // AddNumbers 메서드를 가리키는 델리게이트 생성
int result = add(2, 3); // 델리게이트 호출
람다식 : 람다식은 익명 함수를 정의하는 방법으로, 메서드의 구체적인 이름을 사용하지 않고도 직접 인라인으로 함수를 정의할 수 있다.
람다식은 메서드 시그니처를 생략하고 표현식으로 함수의 동작을 정의한다. 또한 람다식은 익명 함수를 간편하게 정의할 수 있다.
Func<int, int, int> add = (x, y) => x + y; // 람다식을 사용한 델리게이트 초기화
int result = add(2, 3); // 람다식을 통한 델리게이트 호출
람다식은 델리게이트에 비해서 비교적 간결하고 가독성 높은 코드 구현을 제공하지만, 상대적으로 간단한 함수를 정의하는 데 사용되며, 델리게이트는 복잡한 메서드를 가리키거나 대리자 역할을 수행할 때 유용하다.