C# 이것저것/초보자를 위한 C#200제

[C#] 델리게이트의 기본

agingcurve 2024. 2. 1. 13:55
반응형

 

정수 배열에서 홀수와 짝수의 갯수를 출력하고 싶을 때,

int[] arr = new int[] { 3, 5, 4, 2, 6, 4, 6, 8, 54, 23, 4, 6, 4 };

Console.WriteLine($"짝수의 갯수 : {Count(arr, IsEvne)}");
Console.WriteLine($"홀수의 갯수 : {Count(arr, IsOdd)}");

 

이것을 구분하기 위해 홀과 짝을 구분하는 메서드 를 만들어서 구분할 수 있다.

 

static int EvenCount(int[] a) // 짝수
{
    int cnt = 0;
    foreach (var n in a)
    {
        if (n%2==0)
        {
            cnt++;
        }
    }
    return cnt;
}
static int OddCount(int[] a) //홀수
{
    int cnt = 0;
    foreach (var n in a)
    {
        if (n%2!=0)
        {
            cnt++;
        }
    }
    return cnt;
}

 

두 메스드를 보면 n%2가 0인지 1인지 판단하는 if문을 제외하고는 완전히 동일한 코드이다. 이것을 하나로 만들어서 사용할 수 없을까?

이럴때 사용하는 것이 델리게이트다 델리게이트는 대리자라는 뜻으로, 메서드의 참조, 즉 C언어의 함수 포인터와 같은 개념이다.

델리게이트는 delegate 키워드를 사용해서 메서드의 선언처럼 사용한다.

delegate 리턴형식 이름(매개변수 목록);

 

 

델리게이트를 이용해서 홀과 짝을 구분해보자

using System;

namespace A113_DelegateExample
{
    class Program
    {
        delegate bool MemberTest(int a); //델리게이트 선언 리턴 값이 bool 형태로 사용ㅇ


        static int Count(int[] a , MemberTest testMehthod) //배열과 같이 델리게이트형식으로 함수명을 넣어준다
        {
            int cnt = 0;
            foreach(var n in a)
            {
                if (testMehthod(n) == true) //델리게이트를 통해 bool 형태로 참과 거짓을 구분
                    cnt++; // 리턴값이 true일경우 1씩 증가시켜 리턴
            }
            return cnt;
        }

        static public bool IsOdd(int n) { return n % 2 != 0; }
        static public bool IsEvne(int n) { return n % 2 == 0; }
        static void Main(string[] args)
        {
            int[] arr = new int[] { 3, 5, 4, 2, 6, 4, 6, 8, 54, 23, 4, 6, 4 };

            Console.WriteLine($"짝수의 갯수 : {Count(arr, IsEvne)}");
            Console.WriteLine($"홀수의 갯수 : {Count(arr, IsOdd)}");
        }
    }

}

 

 

짝수와 홀수를 출력을 델리게이트를 사용하였다.


IsOdd()와 IsEven() 메서드는 MemberTest의 델리게이트 메서드가 사용되었다. 그런데 이 메서드들은 한번씩만 사용되었기 때문에 메서드 정의를 하지않고 이름없이 인라인(Inline) 함수로 만들 수 있다. 이것을 무명 또는 익명 델리게이트(Anonymous Delegate)이다.

 

using System;


namespace A114_AnonymousDelegate
{
    class Program
    {
        delegate bool MemberTest(int x); //델리게이트 선언
        static void Main(string[] args)
        {
            var arr = new[] { 3, 34, 6, 34, 7, 8, 24, 3, 675, 8, 23 };

            int n = Count(arr, delegate (int x) { return x % 2 == 0; }); //메서드를 이름없이 인라인으로 직업 정의 (Anonymous Delegate) 따로 함수를 정의하지 않아도 사용
            Console.WriteLine($"짝수의 갯수 : {n}");
            n = Count(arr, delegate (int x) { return x % 2 != 0; });
            Console.WriteLine($"홀수의 갯수 : {n}");
        }

        static int Count(int[] a, MemberTest testMehthod)
        {
            int cnt = 0;
            foreach (var n in a)
            {
                if (testMehthod(n) == true)
                    cnt++;
            }
            return cnt;
        }
    }

 

 

델리게이트를 사용하려면 우선 delegate를 선언해야 하는데, 이것도 사실은 번거롭다. .NET에서는 Func와 Action 델리게이트를 미리 만들어서 제공한다.

이것을 사용하면 delegate를 선언할 필요가 없다. Func 델리게이트는 결과를 반환하는 메서드를 참조하기 위해, Action 델리게이트는 반환 값이 없는 메서드를 참조한다.

 

Func와 Action은 제네릭(Generic) 매개변수를 사용한다. Func(int, bool)은 매개변수로 int 하나를 갖고 리턴 값이 bool인 델리게이트이다.

매개변수가 없는 것부터 16개가 있는 것까지 제공하므로 거의 모든 Delegate를 Func와 Action으로 사용이 가능하다.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace A115_FuncAndAction
{
    class Program
    {
        static void Main(string[] args)
        {
            //Func를 사용하므로 델리게이트를 선언하지 않는다.
            var arr = new[] { 3, 34, 6, 34, 7, 8, 24, 3, 675, 8, 23 };
            int n = Count(arr, delegate (int x) { return x % 2 == 0; });
            Console.WriteLine($"짝수의 갯수 = {n}");
            int s = Count(arr, delegate (int x) { return x % 2 != 0; });
            Console.WriteLine($"홀수의 갯수 = {s}");
        }

        private static int Count(int[] arr, Func<int, bool> testMethod) //Count() 메서드는 배열과 델리게이트 메서드를 매개변수로 한다. 
        {                                                               //메서드는 이름 없이 무명 델리게이트로 정의
            int cnt = 0;
            foreach (var n in arr)
            {
                if (testMethod(n))
                    cnt++;
            }
            return cnt;
        }
    }
}