일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- C#
- 코테
- Beakjoon
- Algorithm
- 코딩테스트
- 백준 1103번
- Unity
- 백준 c++ 2468번
- 2468 c++
- 유니티
- 2870번 수학숙제
- 백준
- 2870번 c++
- 프로그래머스
- 플레이어 이동
- 백준 2870번
- 오브젝트 풀링
- 백준 17070번
- Lv2
- 백준 c++ 2870번
- c++
- Lv.3
- 백준 17070번 c++
- 2870번
- 수학숙제
- 17070번
- 백준 1103번 게임
- 2870번 수학숙제 c++
- dfs
- 백준 1103번 c++
- Today
- Total
주녘공부일지
[C#] 대리자 (Delegate - Action, Func) 본문
대리자 (Delegate)
어떤 메서드를 호출하는 방법을 담은 객체
- C의 함수 포인터 같은 지연 호출 수단 등과 같이 프로그래밍 언어에서 말하는 Callback과 유사
- 제네릭 대리자 형식으로 선언할 수도 있으며, 제네릭 형식 매개변수를 둘 수도 있음
https://godgjwnsgur7.tistory.com/115
ex) 대리자 인스턴스, 호출, 대리자를 이용한 플러그인 메서드
// 제네릭 대리자 형식
public delegate T Transformer<T>(T arg);
class Util
{
// 제네릭 형식 매개변수로 변환 플러그인 메서드를 받아 배열의 값을 변경하는 메서드
public static void Transform<T>(T[] values, Transformer<T> t)
{
for (int i = 0; i < values.Length; i++)
values[i] = t(values[i]);
}
}
class Test
{
static int Square(int x) => x * x;
static void Main()
{
Transformer t = Square; // 대리자 인스턴스 생성 = new Transformer(Square)
int result = t(3); // 대리자 호출 = t.Invoke(3)
Console.WriteLine(result); // 9
int[] values = { 1, 2, 3 };
Util.Transform(values, Square); // Square 메서드를 적용
foreach (int i in values)
Console.Write(i + " "); // 1 4 9
}
}
1) 다중 캐스트 대리자
하나의 대리자 인스턴스는 여러 개의 대상 메서드들을 지칭 가능
- 대리자 인스턴스에 +=나 -= 연산자를 이용해 메서드를 추가, 제거 할 수 있음
- 만약, 반환 형식이 void가 아닐 경우엔 마지막 호출 메서드의 반환 값을 받게 됨
- '+=' 연산자로 수행되는 메서드 추가는 같은 메서드라고 해도 중복이 가능하므로 주의
+ 대리자는 불변이 객체로, +=나 -= 연산 시에 새로운 대리자 인스턴스가 생성되어 기존 변수에 배정
SomeDelegate d = SomeMethod1;
d.Invoke() // SomeMethod1 실행
d += SomeMethod2;
d.Invoke(); // SomeMethod1, SomeMethod2 실행
d -= SomeMethod1;
d.Invoke(); // SomeMethod2 실행
d -= SomeMethod2; // d는 null이 되며, Invoke 호출 시 예외가 던져짐
+ 메서드 대상이 동일한 대리자 인스턴스들은 서로 같다고 간주되는데, 다중 캐스트 대리자는 같은 대상 메서드들이 같은 순서로 등록되어 있어야 서로 같다고 간주됨
2) 제네릭 대리자 형식 ( 표준 Func 대리자, Action 대리자 )
https://godgjwnsgur7.tistory.com/115
- 임의의 반환 형식과 임의의 개수의 매개변수들을 가진 그 어떤 메서드에도 작동할 정도로 일반적인 대리자 형식들 몇 개만 작성하여 재사용하는 것이 가능
ex) System 이름공간에 정의된 Func 대리자들과 Action 대리자들
delegate TResult Func<out TResult>();
delegate TResult Func<in T, out TResult>(T arg);
delegate TResult Func<in T1, T2, out TResult>(T1 arg1, T2 arg2);
// ... 이와 비슷한 선언들이 T16까지 이어짐
delegate void Action();
delegate void Action<in T>(T arg);
delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
// ... 이와 비슷한 선언들이 T16까지 이어짐
ex) 이전 예제의 Transformer 대리자를 T 형식의 인수를 하나 받아 같은 형식의 값을 돌려주는 Func 대리자로 대신함
pbulic static void Transform<T> (T[] values, Func<T, T> transformer)
{
for(int i = 0; i < values.Length; i++)
values[i] = transformer(values[i]);
}
- 실무에서 이 대리자들로 해결되지 않는 경우는 ref, out, 포인터 매개변수 뿐이라고 할 수 있음
3) 대리자의 호환성 ( 반변성, 공변성, 가변성 )
- 모든 대리자 형식은 다른 모든 대리자 형식과 호환되지 않음 ( 서명이 같더라도 호환되지 않음 )
delegate void D1();
delegate void D2();
D1 d1 = Method1;
D2 d2 = d1; // 컴파일 시점 오류
D2 d2 = new D2(d1); // 가능한 코드
1. 매개변수 호환성 ( 반변성, contravariance )
- 대리자의 매개변수 형식이 대상 메서드의 매개변수 형식보다 더 구체적일 수 있음
- 오직 참조 변환에 대해서만 작동함
ex) 대리자 반변성 예제 - string 형식 인수로 StringAction 인스턴스 호출
delegate void StringAction(string s);
class Test
{
static void Main()
{
StringAction sa = new StringAction(ActOnObejct);
sa ("hello"); // string -> object 암묵적 상향 캐스팅
}
static void ActOnObejct(object o) => Console.WriteLine(o); // hello
}
2. 반환 형식 호환성 ( 공변성, covariance )
- 대리자는 대상 메서드의 반환 형식보다 더 구체적인 형식을 돌려줄 수 있음
ex) 대리자 공변성 예제 ( 대리자의 반환 형식은 공변 )
delegate object ObjectRetriever();
class Test
{
static void Main()
{
ObejctRetriever o = new ObjectRetriever(RetrieveString);
object result = o();
Console.WriteLine(result); // hello
}
static string RetrieveString() => "hello";
}
제네릭 대리자 형식 매개변수의 가변성
제네릭 대리자 형식을 정의할 때에는 다음과 같은 관행을 따르는 것이 좋음
- 반환 값에만 쓰이는 형식 매개변수는 공변으로 지정 (out 수정자)
- 매개변수에만 쓰이는 형식 매개변수는 반변으로 지정 (in 수정자)
-> 형식들 사이의 상속 관계에 대한 형식 변환이 자연스럽게 일어남
delegate TResult Func<out TResult>(); // 형식 매개변수 TResult는 공변
delegate void Action<in T>(T arg); // 형식 매개변수 T는 반변
ex) 따라서 다음과 같은 용법이 허용
Func<string> x = ...;
Func<object> y = x;
Action<object> x = ...;
Action<string> y = x;
참고도서) C# 6.0 완벽가이드
'Programming > Definition, Etc' 카테고리의 다른 글
[C#] 이벤트 (Event) + 표준 이벤트 패턴, 이벤트 접근자&수정자 (0) | 2023.11.15 |
---|---|
[C#] 대리자(delegate) vs 인터페이스(interface) (0) | 2023.11.10 |
[C#] 제네릭 (Generic) (0) | 2023.10.27 |
[C#] 열거형 (enum type) (1) | 2023.10.15 |
[C#] 인터페이스 ( interface ) (0) | 2023.10.12 |