프로그래밍/C#

[C#] Delegate Example

갓똥 2020. 4. 6. 18:15
728x90
반응형

1. 예제

using System;

class Program {
    public static void Swap(ref int a, ref int b) {
        int temp = a;
        a = b;
        b = temp;
    }
    
    public static void Sort(int[] arr) {
        int sz = arr.GetLength(0);
        
        for(int i = 0; i < sz -1; i++) {
            for(int j = i + 1; j < sz; j ++) {
                if(arr[i] > arr[j])
                    Swap(ref arr[i], ref arr[j]);
            }
        }
    }
    
    static void Main() {
        int[] x = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
        
        Sort(x);
        
        foreach(int n in x)
            Console.WriteLine(n);
    }
}

 

위의 코드는 Main의 배열 x를 오름차순으로 정렬해주는 코드이다.
Swap 같은 경우 실제 값을 바꿔야 하기에 ref 로 인자를 전달 받는다.
Sort에서 배열의 앞과 뒤를 비교해 크면 자리를 바꾸어 정렬하는 간단한 코드인데
현재 문제는 오름차순만 된다.
내림차순으로 바꾸려면 15번째 라인의 if(arr[i] > arr[j])를 if(arr[i] < arr[j])로 바꾸어야 한다.
근데 일반적으로 이러한 Sort는 라이브러리의 내부 코드일 확률이 높다.
그런데 사용자가 오름차순, 내림차순을 정하기 위해 내부 코드를 마음대로 수정하는것은 안된다.
그렇다면 사용자가 사용할 때 오름차순, 내림차순을 정해서 Sort하는게 편할 것이다.
즉, 15번 라인의 비교연산자를 >로 쓸지 <로 쓸지를 정하면 좋을 것이다.
이럴 경우 변하는 부분인 15번 라인을 함수 인자로 뽑고 시작한다.

 ① 공통성과 가변성의 분리

    => 변하지 않는 코드 내에 있는 변하는 코드는 분리한다.

    => 알고리즘은 변경되지 않는데, 정책을 변경하고 싶은 경우

    => 변하는 부분(정책)을 함수 인자로 변경한다 => delegate

 

using System;

delegate int Comparison(int arg1, int arg2);

class Program {
    public static void Swap(ref int a, ref int b) {
        int temp = a;
        a = b;
        b = temp;
    }
    
    public static void Sort(int[] arr, Comparison cmp) {
        int sz = arr.GetLength(0);
        
        for(int i = 0; i < sz -1; i++) {
            for(int j = i + 1; j < sz; j ++) {
                // if(arr[i] > arr[j])
                if(cmp(arr[i], arr[j]) > 0)
                    Swap(ref arr[i], ref arr[j]);
            }
        }
    }
    
    static void Main() {
        int[] x = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
        
        Sort(x, 
            delegate(int a, int b) {return a > b ? 1 : -1; });
        
        foreach(int n in x)
            Console.WriteLine(n);
    }
}

 

먼저 17번 라인을 인자로 뺐다.
인자는 비교에 필요한 메소드를 받아야 하므로 delegate를 만들었다.
Comparison이란 delegate는 비교를 위한 int형 인자 2개를 받고 int타입을 반환한다.
또 인자로 받은 Comparison을 사용하여 0보다 클 경우 Swap을 하도록 했다.
이제 비교하는 메소드를 만들어야 한다.
Main밖에 만들어도 되지만 이전 포스트에서 쓴 익명 메소드를 사용해 27~28번 라인과 같이 작성했다.
28번 라인에서 a > b로 할 경우 오름차순이 되고, a < b로 할 경우 내림차순이 된다.
이로써 알고리즘 자체는 변경되지 않지만
사용자가 정책을 결정해 원하는 순서로 정렬할 수 있게 되었다.
마지막으로 위의 코드를 좀 더 발전시켜보자.
using System;

delegate int Comparison<T>(T arg1, T arg2);

class Program {
    public static void Swap(ref int a, ref int b) {
        int temp = a;
        a = b;
        b = temp;
    }
    
    public static void Sort(int[] arr, Comparison<int> cmp) {
        int sz = arr.GetLength(0);
        
        for(int i = 0; i < sz -1; i++) {
            for(int j = i + 1; j < sz; j ++) {
                if(cmp(arr[i], arr[j]) > 0)
                    Swap(ref arr[i], ref arr[j]);
            }
        }
    }
    
    static void Main() {
        int[] x = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
        
        Sort(x, 
            delegate(int a, int b) {return a > b ? 1 : -1; });
        
        foreach(int n in x)
            Console.WriteLine(n);
    }
}

 

현재 문제는 Sort가 int타입에 대해서만 가능하다는 것이였다.
하지만 delegate를 만들 때 Comparison을 Generic으로 만들어 모든 타입에 대해 가능하게 되었다.

 


2. 추가

위의 코드에서 Comparison과 Sort는 사실 C#에 이미 정의되어있다.

 ① Comparison<T>

    => 두 수를 비교하는 메소드를 담은 generc delegate

 

 ② Array 클래스

    => 배열에 적용할 수 있는 다양한 static method 제공

    => Array.Sort()

Array.Sort(x);  // 오름차순

Array.Sort(x,
    delegate(int a, int b) { return a < b ? 1 : -1; }
    );          // 내림차순
728x90
반응형