C#

delegate (대리자), Event

게임만드는학생 2025. 1. 20. 12:51

 

delegate 대리자, 말 그대로 직접호출하는 대신 특정한 때에, 내가 넘겨준 함수를 실행해주세요. 하고 맡기는 것이다. 

 

delegate 는 함수자체를 형식으로 지정하고 이를 매개변수로 넘겨줄 수 있다.

 

delegate string InfoPrint();

void PrintInfo(InfoPrint info)
{
	info();
}

string TestDelegate()
{
	Console.WriteLine("Info");
    return "Info";
}

main()
{
    InfoPrint ip = new InfoPrint(TestDelegate);
    ip();
    
    PrintInfo(TestDelegate);
}

먼저 delegate 형식을 선언한다. 함수자체를 형식으로 만드는 것이기에 반환형 string에 이름 InfoPrint, 입력 없음으로 delegate 형식을 만든 것이다. 

 

먼저 PrintInfo 함수를 보면 매개변수로 delegate 를 받는 모습이다. info() 방식으로 실행할 수 있다.

그리고 delegate에 넣어줄 함수는 TestDelegate처럼 반환형, 매개변수를 맞춰야한다. 

main에서 보면  객체를 생성하듯 new로 만들 수 있다. 

또는 직접 PrintInfo를 호출하며 delegate를 지정할수도 있다. 

그런데 첫번째 객체방식으로 생성하면 이점이 하나 있다. 

delegate string InfoPrint();

void PrintInfo(InfoPrint info)
{
	info();
}

string TestDelegate()
{
	Console.WriteLine("Info");
    return "Info";
}

string TestDelegate2()
{
	Console.WriteLine("Info2");
    return "Info2";
}
main()
{
    InfoPrint ip = new InfoPrint(TestDelegate);
    ip+=TestDelegate2;
    ip();
    
    PrintInfo(TestDelegate);
}

위 main 에서처럼 delegate 형식에는 하나의 함수만 지정할 수 있는게 아니라 체이닝하여 여러개의 함수가 실행되도록 할 수도 있다. ip()가 실행되면 Info, Info2 가 차례로 출력된다. 

 

근데 여기서 PrintInfo에서만 info 가 호출되게 하고 싶지만 현재는 어디에서든 호출을 할 수가 있다. 

만약 info가 다른데서 호출됐을 때, 아주 큰 리스크가 있는 것이라면 위험한 설계가 될 수 있다.

그래서 Event라는 것을 사용한다. 

간단히 말하면 delegate를 한 번 더 매핑한다. 

 

delegate string InfoPrint();

event InfoPrint InfoEvent;

이렇게 매핑을 한다. 그리고 똑같이 InfoEvent에 += 으로 체이닝하거나 -=으로 제거할 수 있다. 

다만 event가 생성된 클래스 내에서만 InfoEvent() 가 가능하다는 점에서 캡슐화할 수 있다. 

 

또한 C#에는 Func와 Action 같은 이미 만들어진 delegate들이 있다.

둘다 제너릭으로 만들어진 델리게이트인데, Func는 반환형이 있을 때, Action은 없을 때 사용하면 된다.