public class MyClass
{
public delegate void Mydel(string message);
public Mydel mydel;
}
static void WriteMessage1(string message)
{ Console.WriteLine("1 : "+message); }
static void WriteMessage2(string message)
{ Console.WriteLine("2 : "+message); }
아래의 글은 클래스 MyClass
와 델리게이트 Mydel
, 그리고 일반 메서드 2가지가 있다고 가정한다.
System.MulticastDelegate
는 System.Delegate
클래스를 상속받은 것으로, 여러 메서드를 할당하고 순서대로 호출할 수 있다.
"+"연산자 혹은 "+="연산자를 사용하면 델리게이트에 메서드를 계속 추가할 수 있다.
연산자가 내부적으로 알아서 처리하기 때문에 메서드 이름만 넣어줘도 되고,
new 키워드를 사용해도 된다.
public class Program
{
void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.mydel += WriteMessage1;
myClass.mydel += WriteMessage2;
// myClass.mydel += new Mydel(WriteMessage2);
myClass.mydel("메서드들 출력")
// "1 : 메서드들 출력"
// "2 : 메서드들 출력"
}
}
MulticastDelegate
를 상속받은 델리게이트는 추가된 메서드들의 리스트인InvocationList
라는 속성을 가지고 있다.
여러 메서드가 할당된 델리게이트가 사용될 때 InvocationList
속성을 통해서 메서드들에 접근할 수 있고 순서대로 메서드를 가져와 호출한다.
Delegate[] invocationList = myClass.mydel.GetInvocationList();
GetInvocationList()
메서드로 델리게이트 내부에 할당된 메서드의 리스트를 가져올 수도 있다.
Delegate Chain
은 MulticastDelegate
과 밀접한 관련이 있다.
여러 델리게이트를 하나로 묶어 하나의 멀티 캐스트 델리게이트로 만드는 것을 Delegate Chain
이라고 한다.
public class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.mydel = (Mydel)Delegate.Combine(
new Mydel(WriteMessage1),
new Mydel(WriteMessage2)
);
myClass.mydel("출력");
}
}
이런 식으로 Delegate.Combine
메서드로 여러 델리게이트를 묶어서 하나의 멀티 캐스트 델리게이트로 만들어줄 수 있다.
이벤트는 델리게이트를 기반으로 하는 특별한 멤버이다.
델리게이트를 좀 더 안정적으로 사용할 수 있도록 도와준다.
이벤트는 멀티 캐스트 델리게이트에 메서드를 추가하는 것과 비슷하지만 몇 가지가 다르다.
"=" 연산자를 사용하여 메서드를 추가할 수 없는 점.
"+=", "-="연산자만 사용가능하다.
직접 클래스 외부에서 이벤트에 접근해서 메서드를 전달하고 호출할 수는 없는 점.
이 부분은 밑에서 더 자세하게..
먼저 선언한 델리게이트와 event 키워드를 사용해서 하나의 이벤트 멤버를 선언할 수 있다.
public class MyClass
{
public delegate void Mydel(string message);
public Mydel mydel;
public event Mydel MyEvent; // 이벤트 선언
}
무조건 "+=", "-="연산자만 사용해서 이벤트에 메서드를 등록, 해제할 수 있다.
public class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.MyEvent += WriteMessage1;
myClass.MyEvent += WriteMessage2;
myClass.MyEvent -= WriteMessage2;
}
}
이 부분은 멀티 캐스트 델리게이트가 여러 메서드를 담고 있을 때
"=" 연산자 하나로 전에 담은 메서드가 전부 날라가버리는 일을 막기 위한 것으로 보인다.
차이점에서 언급한 부분이다.
이벤트의 호출은 클래스 내부에서 다른 메서드를 통해서 이루어져야한다.
말이 더 어려우니 코드를 보자.
public class MyClass
{
public delegate void Mydel(string message);
public Mydel mydel;
public event Mydel MyEvent;
public void ShowSomething(String str)
{
if (MyEvent != null)
MyEvent(str);
}
}
public class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.MyEvent += WriteMessage1;
myClass.MyEvent += WriteMessage2;
// myClass.MyEvent(str); => 직접 접근해서 이벤트 발생은 불가
myClass.ShowSomething("출력");
}
}
MyClass
클래스에 ShowSomething()
메서드를 선언하는데, 그 안에서 이벤트 MyEvent
를 호출한다.
Main
에 중간에 써놓았듯이 외부에서 직접 인자를 넣어서 이벤트를 호출할 수 는 없도록 막혀있다.
나 :
그냥 멀티 캐스트 델리게이트에 메서드를 추가하는 것과
여러 델리게이트를 Delegate.Combine을 이용해서 하나의 멀티 캐스트 델리게이트로 만드는 것은 비슷하지만 다른 것이라고 할 수 있겠네?
ChatGPT :
맞습니다. 멀티캐스트 델리게이트에 메서드를 직접 추가하는 것과 Delegate.Combine을 사용하여 여러 델리게이트를 결합하여 멀티캐스트 델리게이트를 생성하는 것은 약간의 차이가 있습니다.
- 멀티 캐스트 델리게이트에 메서드 직접 추가
MyDelegate multiDelegate = Method1; multiDelegate += Method2; multiDelegate += Method3;
- 델리게이트 체인
MyDelegate multiDelegate = (MyDelegate)Delegate.Combine(new MyDelegate(Method1), new MyDelegate(Method2), new MyDelegate(Method3));
두 방법은 결국 같은 결과를 얻지만, 두 번째 방법은 더 일반적이고 동적인 상황에 유용합니다. Delegate.Combine을 사용하면 여러 델리게이트를 동적으로 결합할 수 있으며, 예를 들어 컬렉션에서 가져온 델리게이트들을 쉽게 합칠 수 있습니다.
이거 글 쓰는데 3시간 걸렸다.. 블로그랑, 공식 문서랑, 지피티에 질문하며 정보가 정확한지 계속 검증해보고, 문장이 말이 되는지 안되는지도 계속 검증해봤다.
그래도 틀린 부분은 존재할 수도 있으니 참고만 해주길 바랍니다.
참고 자료
https://blog.hexabrain.net/151
공식문서 : MulticastDelegate 클래스