1. Delegate란 무엇인가? (이하 델리게이트)
처음 델리게이트를 접했을 땐, 왜 쓰는지도 잘 이해가 안 됐고 단어 자체도 낯설었다.
그럼 그 사용을 한번 알아가보자.
사전에는 어떤 사람이나 그룹을 대신하는 사람이라고 한다.
쉽게 말해 대리인. 대표.
단어 뜻에서 접근하면, 델리게이트란 어떤 것을 대리해주는 느낌이다.
그렇다. 결론부터 말하자면, 델리게이트란 C#에서 메소드를 대신해서 호출한다. (메소드의 대리)
이게 무슨 말인가?
델리게이트가 없으면 메소드를 직접 호출해서 사용하지만,
델리게이트를 사용하면 메소드를 델리게이트를 호출하면서 사용할 수 있다.
역시 설명은 어렵고 예제를 보자.
2. 델리게이트 사용방법
① 호출할 메소드와 같은 타입의 델리게이트를 먼저 선언해야한다.
② 델리게이트를 선언하고 호출할 메소드를 파라미터로 넣어준다.
namespace ForTistory
{
// 여기를 잘 봐보자. 델리게이트를 클래스 밖에 선언해줬다.
// 클래스 안에 선언해도 사용이 가능하다. 다만, 델리게이트가 범용적으로 사용될 것을 감안하면
// 클래스 밖에 선언해주는게 더 용이할 수 있겠다.
delegate int MyDelegate(int a, int b);
class Program
{
// 델리게이트에 전해줄 메소드들.
public static int Plus(int a, int b)
{
return a + b;
}
public static int Times(int a, int b)
{
return a * b;
}
static void Main(string[] args)
{
// 델리게이트 선언. 대리할 메소드를 넣어준다.
MyDelegate myDelegate = new MyDelegate(Plus);
// 델리게이트로 메소드를 호출한다.
int sum = myDelegate(10, 5);
Console.WriteLine("The answer is : {0}", sum);
// myDelegate를 그대로 사용해보자. 새로 선언해도 된다.
myDelegate = new MyDelegate(Times);
result = myDelegate(10, 5);
Console.WriteLine("The answer is : {0}", result);
}
}
}
어떤가? 메소드를 대신한다는게 이해가 되는가? 코드를 자세히 봐보자.
"뭐야? 메소드를 그냥 호출하는 거에 비해 뭐가 좋다는거야?" 라고 의문이 들 수 있다.
맞다. 델리게이트는 저렇게 사용하는 건 큰 의미가 없다.
3. 델리게이트의 진미
자 그럼 델리게이트를 더 유용하게 사용해보자.
어디에 사용할 수 있을까? 바로 콜백 메소드이다.
계산기를 만들어볼 예정이다.
namespace ForTistory
{
// 여기를 잘 봐보자. 델리게이트를 클래스 밖에 선언해줬다.
// 클래스 안에 선언해도 사용이 가능하다. 다만, 델리게이트가 범용적으로 사용될 것을 감안하면
// 클래스 밖에 선언해주는게 더 용이할 수 있겠다.
delegate int MyDelegate(int a, int b);
class Program
{
// 델리게이트를 인자로 받는 메소드.
public static int Calculator(int a, int b, MyDelegate myDelegate)
{
// 파라미터로 받은 델리게이트를 반환한다. 신기한 것은 메소드의 리턴은 int인데 델리게이트를 리턴할 수 있다.
// 왜냐하면, 델리게이트의 리턴값이 인트이기 때문.
return myDelegate(a, b);
}
// 델리게이트에 전해줄 메소드들.
public static int Plus(int a, int b)
{
return a + b;
}
public static int Minus(int a, int b)
{
return a - b;
}
public static int Times(int a, int b)
{
return a * b;
}
static void Main(string[] args)
{
// 메소드를 대신할 델리게이트들을 선언한다.
MyDelegate myPlus = new MyDelegate(Plus);
MyDelegate myMinus = new MyDelegate(Minus);
MyDelegate myTimes = new MyDelegate(Times);
// 계산기에 어떤 델리게이트를 사용할 지를 같이 보내준다.
Console.WriteLine(Calculator(5, 10, myPlus));
Console.WriteLine(Calculator(5, 10, myMinus));
Console.WriteLine(Calculator(5, 10, myTimes));
}
}
}
계산기 메소드에 델리게이트가 들어가서, 델리게이트가 대신하는 메소드를 호출한 뒤에 리턴값으로 보내준 거다.
신기하지 않는가? 마치, 계산기에 더하기, 빼기, 곱하기 등을 작동시키는 느낌이다.
(델리게이트 및 메소드 반환값을 int로 해서 나누기는 제외했다.)
이걸 그냥 메소드로 구성했다면 어땠을까?
namespace ForTistory
{
class Program
{
public static int Calulator(int a, int b, string func)
{
if (func.Equals("Plus"))
{
return a + b;
} else if (func.Equals("Minus"))
{
return a - b;
} else if (func.Equals("Times"))
{
return a * b;
}else
{
return 0;
}
}
static void Main(string[] args)
{
Console.WriteLine(Calculator(5, 10, Plus));
Console.WriteLine(Calculator(5, 10, Minus));
Console.WriteLine(Calculator(5, 10, Times));
}
}
}
이렇게 보니 이게 더 간결하고 보기 좋은 것 같기도...?
간결한 코드가 더 보기 좋은데 왜 델리게이트를 사용하는가?
그에 대해선 마지막에 다뤄보자.
4. 제네릭을 사용한 델리게이트
델리게이트에도 제네릭을 사용해서 형식을 좀더 확장시킬 수 있다. 위의 예제를 아래처럼!
namespace ForTistory
{
delegate T MyDelegate<T>(T a, T b);
class Program
{
public static T Calculator<T>(T a, T b, MyDelegate<T> myDelegate)
{
return myDelegate(a, b);
}
public static int Plus(int a, int b)
{
return a + b;
}
public static float Minus(float a, float b)
{
return a - b;
}
public static double Times(double a, double b)
{
return a * b;
}
static void Main(string[] args)
{
MyDelegate<int> myPlus = new MyDelegate<int>(Plus);
MyDelegate<float> myMinus = new MyDelegate<float>(Minus);
MyDelegate<double> myTimes = new MyDelegate<double>(Times);
Console.WriteLine(Calculator(5, 10, myPlus));
Console.WriteLine(Calculator(5, 10, myMinus));
Console.WriteLine(Calculator(5, 10, myTimes));
}
}
}
5. 델리게이트 체인
델리게이트는 마치! Queue처럼 사용할 수도 있다.
하나의 델리게이트에 여러 개의 메소드를 엮는 것이다.
그래서 이름이 델리게이트 체인이다. 델리게이트를 호출하면 처음부터 넣어진 순서대로 메소드를 호출한다.
namespace ForTistory
{
delegate void MyDelegate();
class Program
{
public static void FuncA() { Console.WriteLine("메소드 A"); }
public static void FuncB() { Console.WriteLine("메소드 B"); }
public static void FuncC() { Console.WriteLine("메소드 C"); }
static void Main(string[] args)
{
MyDelegate myDelegate = new MyDelegate(FuncA);
myDelegate += FuncB;
myDelegate += FuncC;
myDelegate();
Console.WriteLine("-----------");
myDelegate -= FuncA;
myDelegate();
}
}
}
델리게이트 체인의 응용은 알아서...
6. 델리게이트의 응용
델리게이트는 메소드를 대신한다고 했다. 그럼 메소드를 사용해도 되는데 왜 델리게이트를 사용할까?
이는 델리게이트를 자세히 살펴보면 어디에 쓰일 수 있을지 감이 온다.
그럼 한번 알아보자.
자, 3번 단락에서 델리게이트를 선언할 때 어떻게 했는가?
MyDelegate myPlus = new MyDelegate(Plus);
이렇게 하였다. 형태가 익숙하지 않은가? 맞다. 클래스나 참조형식을 선언할 때와 매우 닮았다.
이 말은 무슨 뜻인가? 바로 델리게이트가 객체라는 것이다.
그러니까 메소드는 "객체의 행동"이지 "객체"라고 보지 않는다.
하지만, 메소드에 델리게이트를 씌우면 메소드는 객체가 될 수 있다.
델리게이트가 이러한 특징을 가졌다는 것을 인지하며 사용하길 바란다.
그냥 메소드에 그치지 않고 객체로의 사용으로 확장할 수 있다는 것..
또 무슨 특징이 있을까?
델리게이트는 C#이 발전하면서 비동기 처리(asynchronous operation)에서도 유용하다.
이를 알아보려면 비동기처리에 대해 먼저 알아야하니,
여기선 이정도만 알아가고 나중에 비동기 처리를 할 때 델리게이트가 어떻게 쓰이는지 알아보자.
* 일단, 델리게이트는 쓰레드와 코드를 분리한다는 개념만... 참고
위에 본 것은 일반적인 델리게이트(untyped delegate)라고 하고,
C#에는 델리게이트를 좀더 유용하게 사용할 수 있는 Func 과 Action (typed delegate) 라는 개념이 있다.
( Predicate도 있다. 얘는 special delegate라고 한다. )
이것들은 델리게이트만 안다면 크게 어렵지 않으니 나중에 알아보자.
'개발 > C#' 카테고리의 다른 글
List - 리스트 (0) | 2020.07.14 |
---|---|
값형식과 참조형식 (0) | 2020.07.13 |
Stack and Heap (0) | 2020.07.13 |
? / ?? - C#의 물음표 (0) | 2020.07.13 |
Property - 프로퍼티 (3) | 2020.07.09 |
댓글