프로그래밍/C#

[C#] Delegate Chain

갓똥 2020. 4. 7. 16:44
728x90
반응형

1. Delegate Combine

using System;

class Test {
    public static int Method1() {
        Console.WriteLine("Method1");
        return 1;
    }
    
    public static int Method2() {
        Console.WriteLine("Method2");
        return 2;
    }
    
    public static int Method3() {
        Console.WriteLine("Method3");
        return 3;
    }
    
    public static int Method4() {
        Console.WriteLine("Method4");
        return 4;
    }
}

delegate int FUNC();

class Program {
    public static void Main() {
        FUNC f1 = Test.Method1;
        FUNC f2 = Test.Method2;
        FUNC f3 = Test.Method3;
        
        // 1. Delegate Combine
        FUNC f4 = (FUNC)Delegate.Combine(f1, f2);     // - ok
        // FUNC f4 = (FUNC)Delegate.Combine(f1, f2, f3); - ok
        // FUNC f4 = (FUNC)Delegate.Combine(f1, Test.Method4);  - error
        f4();  // Method1, Method2 호출
        
        // 2. +, -, +=, -=
        FUNC f5 = f1 + f2;     //  - ok
        // FUNC f5 = f1 + f2 + f3; - ok
        // FUNC f5 = f1 + Test.Method4 + f2; - ok
        f5();  // Method1, Method2 호출
    }
}

 ① Delegate.Combine(delegate1, delegate2, ...)

    => 기존의 delegate를 결합한 새로운 delegate 객체 반환

    => Method 이름을 직접 사용할 수는 없음

 

 ② +, +=, -, -= 연산자

    => Delegate 이름 또는 Method 이름을 사용한 결합

 

 ③ Delegate는 immutable 하다.

    => 기존의 delegate 객체에 추가되는 것이 아닌 새로운 delegate 객체를 생성하는 것

delegate는 reference type이다.
FUNC f6 = Test.Method1; 으로 객체를 만들고
FUNC f7 = f6; 으로 복사한다면
둘은 Heap에 같은 곳을 보게되므로 == 연산자를 통해 비교하면 true가 나온다.
여기서
f6 += Test.Method2; 를 하게 된다면
f6 = f6 + Test.Method2; 와 같은 코드가 아니라
f6 = new FUNC( ... ) 와 같은 코드가 되어서 f7은 변하지 않는다.
그리고 둘은 다른 객체가 된다 (==연산자 시 false)

 


2. Delegate Chain 리턴 값

using System;

class Test {
    public static int Method1() {
        Console.WriteLine("Method1");
        return 1;
    }
    
    public static int Method2() {
        Console.WriteLine("Method2");
        return 2;
    }
    
    public static int Method3() {
        Console.WriteLine("Method3");
        return 3;
    }
    
    public static int Method4() {
        Console.WriteLine("Method4");
        return 4;
    }
}

delegate int FUNC();

class Program {
    public static void Main() {
        FUNC uni = Test.Method1;
        
        int ret1 = uni();
        Console.WriteLine(ret1); // 1
        
        
        FUNC multi = Test.Method1;
        multi += Test.Method2;
        multi += Test.Method3;
        multi += Test.Method4;
        
        int ret2 = multi();
        Console.WriteLine(ret2); // 4
    }
}

 

실행 결과

Method1
1
Method1
Method2
Method3
Method4
4
multi는 메소드4개를 가지고 있지만 반환값은 마지막 메소드 하나이다.
하다보면 모든 메소드의 반환값을 받고 싶을 때도 있을텐데
GetInvocationList() 라는 메소드를 사용해서 얻을 수 있다.
메소드를 사용하면 모든 반환값이 배열형태로 반환된다.
Delegate타입의 배열을 만들어 받고
foreach문을 통해 하나씩 돌려주면 된다.
using System;

class Test {
    public static int Method1() {
        Console.WriteLine("Method1");
        return 1;
    }
    
    public static int Method2() {
        Console.WriteLine("Method2");
        return 2;
    }
    
    public static int Method3() {
        Console.WriteLine("Method3");
        return 3;
    }
    
    public static int Method4() {
        Console.WriteLine("Method4");
        return 4;
    }
}

delegate int FUNC();

class Program {
    public static void Main() {
        FUNC multi = Test.Method1;
        multi += Test.Method2;
        multi += Test.Method3;
        multi += Test.Method4;
        
        Delegate[] arr = multi.GetInvocationList();
        
        foreach(Delegate d in arr) {
            FUNC f = (FUNC)d;
            int ret = f();
            Console.WriteLine(ret);
        }
    }
}

 

실행 결과

Method1
1
Method2
2
Method3
3
Method4
4

 ① Multicast Delegate의 반환값 얻기

    => GetInvocationList() 사용

728x90
반응형