모든 델리게이트는 Multicast Delegate라던데...

단일 메서드를 가진 델리게이트가 따로 구분되지 않는 것 같던데…

델리게이트는 여러 메서드를 참조해뒀다 호출할 수 있으니, 내부적으로 호출 목록이 있겠죠?

델리게이트를 단일 메서드 참조용으로 사용하는 경우가 많던데,

단일 메서드를 호출하는 용도로 쓰일 때… 호출 목록을 확인하는 작업이 불필요하게 추가되지 않을까요?

그럼에도 불구하고 인터페이스보다 빠르거나 비슷하던데, 구현이 어떤 식으로 되어 있는 걸까요…

있습니다. 그래서, +=, -= 연산자를 사용하는 것이구요.

그러한 용도에 사용이 가능합니다. 이 경우, 델리게이트의 생성자에 (암묵적으로) 기대는 경우가 많습니다. .

void Execute(Action action) =>  action();

void PrintTime() => Console.WriteLine(DateTime.Now);

아래의 사용 코드는 Action의 생성자를 암묵적으로 호출합니다.

Execute(PrintTime); // action = new Action(PrintTime)
Execute(() => Console.WriteLine(DateTime.Now)); // action = new Action(람다)

이렇게 생성자에 기대는 이유는 델리게이트 객체의 상태를 관리하기 귀찮아서… ^^
닷넷에서는 델리게이트 상태를 잘 관리하라고 하죠.

// 인스턴스멤버
private Action _actions = new();

void NotManageState()
{
    _actions += PrintTime;
    _actions();
   // _actions 의 내부에 PrintTime 이 저장되어 있음. 
}

void ManageState()
{
    _actions += PrintTime;
    _actions();
    _actions -= PrintTime;
}

void DontCareState()
{
    Execute(PrintTime); 
}
3개의 좋아요

System.MulticastDelegate 클래스를 디컴파일 해보면 호출 목록을 담고 있는 _invokationList 필드가 object 형식으로 선언 되어 있습니다.

Delegate 타입 필드에 값을 단일 할당 시에는 _invokationList 필드에 Method 포인터를 직접 저장하고 += 연산자를 통해 추가 할 경우 Delegate.Combine 메소드를 통해 object[] 형식 배열을 생성하여 기존 Method 포인터에 새로운 Method 포인터를 추가합니다.

그래서 Delegate 호출 시 단일 할당 및 다중 할당 여부에 따라 _invokationList를 단일 객체 또는 배열로 캐스팅하여 직접 호출하거나 목록을 iteration 하면서 여러 번 호출하거나 하는 로직으로 분기됩니다.

referencesource/mscorlib/system/delegate.cs at master · microsoft/referencesource · GitHub
referencesource/mscorlib/system/multicastdelegate.cs at master · microsoft/referencesource · GitHub

7개의 좋아요

http://www.csharpstudy.com/DevNote/Article/14

요글을 읽고 공부했던 게 생각났는데 아예 소스코드를 찍어주셨군용. >ㅁ<b

4개의 좋아요