C#

C# Delegate 그리고 Event

Binceline 2013. 1. 8. 03:15


출처 : http://gameforfun.tistory.com/entry/C-Event-%EA%B4%80%EB%A0%A8

----------

Delegate

Delegate는 한글말로 대리자라 해석한다. 대신 해주는 사람을 뜻하는데, 이와 같은 의미로 특정 일을 대신 해주는 변수(field 에 속함)라 생각하면 된다. 
특정 일을 해준다는 것은 특정 형식의 Method를 대신 실행해준다는 것을 의미한다.
변수라 하면 특정 Type의 클래스와 그 클래스가 실체화한 Instance가 존재하는데 이는 Delegate에서도 마찬가지다.

public delegate void DelegateMemberVariable(int a);

해당 코드를 보면 void라는 리턴 타입에 int형의 인자를 받는 함수를 선언하면  Delegate Type 정의 한것이 되고

DelegateMemberVariable delFunc;

를 함으로써 한개의 변수로서의 역할을 하게 된다.
원래 변수를 사용하기 위해서는 그 변수 클래스의 instance 만들어 줘야 하는데 이는 delegate을 사용하기 위해서도 동일하다.

먼저 대리자가 대신 해줄 일을 정의한다

void Function1(int a) 
{
	print("I'm Function1");	
}

그 뒤 대리자의 Instance 만들어서 멤버 변수에 등록을 시켜준다.

delFunc = new DelegateMemberVariable(Function1);

위의 코드와 같이 등록을 시켜주면 함수와 같이 실행 할 수 있게된다.

delFunc(1);

인자는 자동으로 Function1의 a로 넘어가게 되며, Function1이 실행이되어 콘솔창에 I'm Function1이라는 글자가 출력되게 된다.


Multicast Delegate

MulticastDelegate이라는 클래스가 존재하긴 하지만, 사실상 delegate과 같은 기능을 한다.(아마도...?)

이 기능이 무엇인가 하면, 한개의 대리자가 여러개의 일을 처리하는 것으로 생각하면 된다.

마치 사람에게 일1, 일2, 일3을 주는 것과 같은 원리로, 한 대리자 변수에 여러개의 instance를 등록하여, 여러 Method를 한번에 실행하여 관리하는 것이다.

코드는 다음과 같다.

delegate void DelegateFunction(int a);
DelegateFunction delFunc;
	
void Function1(int a)
{
	print("I'm Function1");	
}
void Function2(int b)
{
	print("I'm function2");
}	
	
void Function3(int c)
{
	print("I'm funcion3");	
}
delFunc = new DelegateFunction(Function1); 
delFunc += new DelegateFunction(Function2);// + 연산자로 추가 등록한다.
delFunc += new DelegateFunction(Function3);
delFunc -= new DelegateFunction(Function1);// - 연산자로 기존에 등록되어있는 일을 취소한다.
delFunc(2);

현재는 반환형이 void라 적절하지 못한 예지만..
만일, 함수를 여러개 등록한 상태에서 반환 되는 값이 필요하다 하면 가장 마지막으로 등록된 함수의 return 값이 받아져 온다는 것을 염두해 두자.

Invoke, BeginInvoke, EndInvoke와 비동기 실행.

Event

Event라는 것은 그러면 무엇일까?
많은 자료들은 delegate과 event의 차이점을 Field이냐 Property냐 로서 구분한다.

햇갈리기 전에 짚고 넘어가야겠다... 일반 수준으로 보면 두개는 기능의 차이가 거의 없다.......(물론 내가 프로그램을 깊에 안짜봐서 일지도 모르지만..)

event라는 것이 한개의 대리자의 그릇(?)으로써 행동하기 때문이다.

C#에서 Property는 멤버 변수같지만 실제로는 함수로써 작동하는 놈들을 뜻한다.  

class TimePeriod
{
    private double seconds;

    public double Hours
    {
        get { return seconds / 3600; }
        set { seconds = value * 3600; }
    }
}


class Program
{
    static void Main()
    {
        TimePeriod t = new TimePeriod();

        // Assigning the Hours property causes the 'set' accessor to be called.
        t.Hours = 24;

        // Evaluating the Hours property causes the 'get' accessor to be called.
        System.Console.WriteLine("Time in hours: " + t.Hours);
    }
}

위의 코드를 보면 Hours라는 Property는 내부적으로 get set을 선언해 주는데 이를 컴파일하면 
get_Hours, set_Hours와 같이 자동적으로 변환되고, 
우리가 Hours를 호출하는 부분에 get_Hours 혹은 set_Hours중 하나의 함수가 불린다고 한다.(여러 사람이 그렇데요)

이렇게 보면 Property는 Field에 속한것이 아닌 멤버 함수에 속하기 때문에 
Interface에서 선언이 가능해진다.

참고로 선언된 event 는 외부에서 Event()와 같이 못쓰기 때문에, 해당 이벤트를 가지고 있는 클래스가 사용해야 한다.

밑에 코드를 참고하자.

public class EventTEst : MonoBehaviour {
	CustomEvent ev;	
	
	void Awake(){
		ev = new CustomEvent();
		ev.myEvent += new CustomEvent.CustomEventDelegate(e_myEvent);
		ev.myEvent += new CustomEvent.CustomEventDelegate(e_MyEvent2);		
	}
	
	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		if(Input.anyKeyDown){
			ev.ActivateEvent("ASDASD",2);//키 입력이 발생하면 특정 함수 실행.	
		}
	}
	
	void e_myEvent(string s)		
	{
		//approach to sender's field and we can manipulate.
		print("DUDE: " + "   " + s);
	}
	
	void e_MyEvent2(string s){
		print("IM EVENT 2");
	}
}

public class CustomEvent
{
	public delegate void CustomEventDelegate(string s);
	public event CustomEventDelegate myEvent;
		
	public void ActivateEvent(string s)
	{		
		myEvent(s);//이벤트 실행 -> myEvent에 등록된 함수들이 s라는 변수를 가지고 실행. 외부에서 실행 못함.
	}                                    
}

반응형