본문 바로가기

C#

[C#] Delegate

◈ 대리자(Delegate)란?

: 함수를 보다 효율적으로 사용하기 위해서 특정 함수 자체를 캡슐화하는 기능을 가지고 있다.



 1단계 Delegate할 함수를 정한다.

: Delegate할 함수를 정한다는 것은 어떠한 함수가 대리자를 통해서 호출될 것인지의 문제이이다.

함수의 형태가 다르면 Delegate를 다르게 만들어주어야 한다.


 2단계 함수에 맞는 Delegate 선언하기

: Delegate를 선언하려면 함수의 시그너쳐(Signature)에 정확하게 일치시켜야 한다. 아래와 같이 Delegate와 함수의 리턴타입과 매개변수를 정확하게 일치시켜서 Delegate를 선언해야 한다.


delegate void SimpleDelegate1(); // Delegate 선언 1 = void F1()

delegate void SimpleDelegate2(int i); // Delegate 선언2 - void F2(int x)


class AType

{

public void F1()

{

// Delegate할 함수 1

System.Console.WriteLine("AType.F1");

}


public void F2(int x)

{

// Delegate할 함수 2

System.Console.WriteLine("AType.F2 x=" + x);

}

}


이름은 상관없지만 함수의 시그너쳐와 Delegate의 시그너쳐는 반드시 일치시켜야 한다.


□ 함수의 시그너쳐

: 오버로딩을 공부할 때 오버로딩 함수를 만드는 방법에 대해 배웠다. 오버로딩 함수의 경우 함수의 시그너쳐를 다르게 해주어야 한다. 즉 함수의 매개변수와 매개변수의 데이터 타입을 다르게 주어야 하는 것이다. 오버로딩에서는 함수의 반환형은 시그너쳐로 이용되지 않지만 Delegate에서는 반환형도 시그너쳐에 포함된다.


 3단계 Delegate할 함수를 포함한 클래스의 객체 만들기

: Delegate할 함수를 정하고 Delegate를 선언했다면 호출할 함수를 준비해야 한다. 함수는 홀로 사용될 수 없기 때문에 일단은 함수를 포함한 클래스의 객체를 만들어야 한다.


class DeleTest

{

public static void main()

{

AType atype = new AType();


}

}


위와 같이 F1()과 F2() 함수가 포함된 AType 클래스의 객체 atype을 선언했다. 그 다음은 atype객체의 함수를 실제 Delegate로 만드는 작업을 해야 한다.


 4단계 Delegate 생성과 호출

: 마지막으로 Delegate 객체를 생성한 후  해당 Delegate를 호출하면 된다. 일반 함수를 호출하드싱 Delegate를 이용해서 함수를 호출하면 되는 것이다.


delegate void SimpleDelegate1();

delegate void SimpleDelegate2(int i);


class AType

{

public void F1()

{

System.Console.WriteLine("AType.F1");

}


public void F2(int x)

{

System.Console.WriteLine("AType.F2 x=" + x);

}

}


class DeleTest

{

public static void Main(string[] args)

{

AType atype = new AType();

SimpleDelegate1 s1 = new SimpleDelegate1(atype.F1);

SimpleDelegate2 s2 = new SimpleDelegate2(atype.F2);


s1();

s2(1000);

}

}



Delegate를 만들 때 생성자의 매개변수로 함수의 이름을 넣어주어야 한다. 함수의 이름을 매개변수로 넣어주면 모든 Delegate만들기 작업은 끝난다.


이제부터는 함수를 호출할 때 객체를 이용하는 것이 아니라 대지라를 이용해서 호출이 가능한것이다. 물론 대리자라 할지라도 함수에 일치하는, 대리자에 맞는 매개변수를 넣어서 대리자를 호출해야 한다.



◈ Delegate를 위한 함수

: Delegate는 함수에 대한 대리자이다. 그렇기 때문에 일반 함수든 스태틱 함수든 상관없이 함수의 형만 정확하다면 Delegate로 해당 함수를 호출할 수 있다.


delegate void TopDelegator(string str);


class Top

{

public static void StaticMethod(string str)

{

Console.Write("Static Method입니다.!!\t");

Console.WriteLine(str);

}


public void NormalMethod(string str)

{

Console.Write("Nomal Method입니다.!!\t");

Console.WriteLine(str);

}

}


class DelegateTest

{

public static void Main()

{

Top t = new Top();

TopDelegator td1 = new TopDelegator(t.NormalMethod);

td1("Jabook");

TopDelegator td2 = new TopDelegator(Top.StaticMethod);

td2("소설같은 C#");

}

}


여기서 중요한 것은 스태틱과 일반 멤버 함수에 상관없이 함수의 시그너쳐만 같다면 동일한 Delegate로 동작시킬 수 있다는 사실이다.함수의 반환형과 함수의 매개변수만 일치시키면 하나의 Delegate로 동작시킬 수 있다.


* Delegate를 왜 사용하는 것일까? Delegate는 함수를 캡슐화한다고 하였다. Delegate 객체를 생성하는 것은 함수의 참조자를 일반화된 형식으로 만든다는 의미를 가지고 있다. 이런 Delegate의 장점은 함수를 하나의 실행 단위로 핸들할 수 있다는데 있다. 만약 Delegate가 없다면 함수를 넘겨주기 위해서 객체를 통째로 넘겨야 한다. 하지만 어떠한 형의 객체를 넘겨주어야 할지 애매해진다. 그래서 규칙을 정하는 것이다.



☞ 참고

: 함수를 넘겨주는 규칙을 Delegate 대신 Interface를 이용해도 된다. 실제 자바에서는 Delegate가 없기 때문에 Interface를 매개체로 함수를 전달한다. Interface를 사용할 경우 문제점은 전달할 함수를 Interface로 매번 구현해야 한다는 점이다. 하지만 Delegate를 이용하면 이러한 절차를 거치지 안하도 된다.


□ Delegate의 해석

-. 함수의 포인터를 편리하게 사용하는 방법을 제공한다.

-. Safe Type Method Pointer

-. Method의 Pointer를 C#에서는 Delegate라는 형식을 빌어 사용할 수 있게 해준다.

-. 함수를 Delegate라는 것에게 관리하게 하고 함수의 반환형과 매개변수 등의 안전성을 보장받는다.


□ Delegate형과 일치시켜야 할 함수의 형태

-. 함수와 Delegate의 반환형

-. 함수와 Delegate의 매개변수 개수

-. 함수와 Delegate의 매개변수 타입



'C#' 카테고리의 다른 글

[C#] MemberwiseClone() 함수  (0) 2018.07.16
[C#] enum의 Flag 연산  (0) 2018.07.16
[C#] Boxing / UnBoxing / as  (0) 2018.07.11
[C#] 서로 다른 3가지 Timer  (0) 2018.07.11
[C#] 마샬링이란(marshalling)  (0) 2018.07.10