대리자, 람다, Action 대리자와 Func 대리자
https://learn.microsoft.com/ko-kr/dotnet/csharp/programming-guide/delegates/
대리자 - C# 프로그래밍 가이드
C#의 대리자는 매개 변수 목록 및 반환 형식이 있는 메서드를 나타내는 형식입니다. 대리자는 메서드를 다른 메서드에 인수로 전달하는 데 사용됩니다.
learn.microsoft.com
특정 매개 변수 목록 및 반환 형식이 있는 메서드에 대한 참조를 나타내는 형식
매개 변수를 통해 메서드를 전달한다. 정확히는 메서드에 대한 참조를 가지는 대리자를 통해 전달
대리자를 인스턴스화하면 모든 메서드가 있는 인스턴스를 호환되는 시그니처 및 반환 형식에 연결할 수 있다.
대리자는 메서드에 대한 참조다.
대리자는 메서드를 다른 메서드에 인수로 전달하는 데 사용된다.
대리자는 메서드에 대한 참조를 가질 수 있는 형식
형식정의
한정자 delegate 반환_형식 대리자_이름 (매개변수_목록);
대리자는 메소드에 대한 참조를 가지기에 메서드 형식과 비슷하다
ex) delegate int MyDelegate(int a, int b)
대리자는 인스턴스가 아닌 형식이다.
메서드를 인스턴스에다가 연결
사용 이유: '값'이 아닌 '코드' 자체를 넘김, 즉 '값'이 아니라 '기능' 자체를 넘긴다.
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
//대리자는 메서드에 대한 참조를 가질 수 있는 형식
//2. 대리자 형식 정의
//한정자 delegate 형식명 연결할 메서드 시그니쳐
delegate void MyDelegate();
//생성자
public App()
{
//3. 대리자 인스턴스 생성 및 연결 (대리자 초기화)
MyDelegate myDel = new MyDelegate(this.SayHello);
//4. 대리자 호출(연결된 메서드 호출)
myDel(); //SayHello()가 호출됨
}
//1. 메서드 정의 (시그니처가 대리자 형식과 같은)
//안녕하세요를 출력하는 메서드
void SayHello()
{
Console.WriteLine("안녕하세요");
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
//2. 대리자 형식 정의
delegate void MyDelegate(string name);
public App()
{
//3.대리자 인스턴스화
MyDelegate myDel = new MyDelegate(this.ByeBye);
//4.대리자 호출
myDel("홍길동");
}
//1.메서드 정의
void SayHello(string name)
{
Console.WriteLine("{0}님 안녕하세요", name);
}
void ByeBye(string name)
{
Console.WriteLine("{0}님 안녕히 가세요~", name);
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
//2.대리자 형식 정의
delegate int MyDelegate(int x, int y);
public App()
{
//3. 대리자 초기화
MyDelegate del = new MyDelegate(Sum);
//4.대리자 실행
del(5,8);
}
//1. 메서드 정의
int Sum(int x, int y)
{
return x + y;
}
}
}
callback
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
//2.대리자 형식 정의
public delegate void MyDelegate();
public App()
{
//3. 대리자 인스턴스화(메서드 연결)
MyDelegate myDel = new MyDelegate(this.HeroMoveComplete);
Hero hero = new Hero();
hero.Move(myDel); //HeroMoveComplete가 연결된 대리자 인스턴스를 인수로 전달
//4.대리자 실행
}
//1. 메서드 정의
void HeroMoveComplete()
{
Console.WriteLine("[App] 영웅이 이동을 완료 했습니다");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnDotnet
{
public class Hero
{
public Hero()
{
Console.WriteLine("영웅이 생성되었습니다");
}
public void Move(App.MyDelegate callback) //App의 멤버인 MyDelegate에 접근
{
Console.WriteLine("영웅이 이동중...");
Console.WriteLine("영웅이 이동중...");
Console.WriteLine("영웅이 이동중...");
Console.WriteLine("영웅이 이동중...");
Console.WriteLine("영웅이 이동중...");
Console.WriteLine("영웅이 이동중...");
Console.WriteLine("영웅이 이동중...");
Console.WriteLine("영웅이 이동을 완료했습니다.");
//4. 대리자 호출
callback();
}
}
}
익명 메서드(이름이 없는 메서드)
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
//1.대리자 형식 정의
delegate void MyDel();
public App()
{
//2.대리자 인스턴스화 (무명 메서드 연결)
MyDel del = delegate () {
Console.WriteLine("안녕하세요");
};
//3. 대리자 호출
del();
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
//1.대리자 형식 정의
delegate void MyDel(string name);
public App()
{
//2.대리자 인스턴스화(익명 메서드 연결)
MyDel del = delegate (string name){
Console.WriteLine("{0}님 안녕하세요", name);
};
//3.대리자 호출
del("홍길동");
}
}
}
람다식은 익명 메소드를 만들기 위해 사용 ---> 람다 선언 연산자 ( => ) 자주 사용하기에 잘 알고 있어야 됨
https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/operators/lambda-expressions
람다 식 - 람다 식 및 익명 함수
익명 함수 및 식 본문 멤버를 만드는 데 사용되는 C# 람다 식입니다.
learn.microsoft.com
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
//1. 대리자 형식 정의
delegate int MyDel(int a,int b);
public App()
{
//2. 대리자 인스턴스화 (익명 메서드 연결, 람다문을 사용해서)
// 대리자 인스턴스 : () => { };, 즉 (=) 뒤에가 인스턴스
//람다에서 형식을 유추하기에 int 같은거 붙일 필요 없음
MyDel del = (a,b) => {
return a + b;
};
//3. 대리자 실행
del(5, 8);
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
//1. 대리자 형식 정의
delegate void MyDel(string name);
public App()
{
//2. 대리자 인스턴스화 (익명 메서드 연결, 람다문을 사용해서)
MyDel del = (name) => {
Console.WriteLine("{0}님 안녕하세요.", name);
};
//3. 대리자 실행
del("홍길동");
}
}
}
람다 응용 callback
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
//1.대리자 형식 정의
public delegate void DelHeroMoveComplete();
public App()
{
//2.대리자 인스턴스화 (람다/ 멤서드 연결)
DelHeroMoveComplete del = () =>{
Console.WriteLine("영웅이 이동을 완료 했습니다");
};
//3. 대리자 던짐
Hero hero = new Hero();
hero.Move(del);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnDotnet
{
public class Hero
{
public Hero()
{
Console.WriteLine("영웅이 생성되었습니다");
}
public void Move(App.DelHeroMoveComplete callback)
{
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동완료");
callback();
}
}
}
Action 대리자와 Func 대리자
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
public App()
{
//대리자 변수 정의
Action action;
//대리자 인스턴스화 (메서드 연결)
action= this.SayHello;
action = () =>{
Console.WriteLine("Hello");
}; //람다문
action();
}
void SayHello()
{
Console.WriteLine("안녕");
}
}
}
https://learn.microsoft.com/ko-kr/dotnet/api/system.func-3?view=net-7.0
Func<T1,T2,TResult> 대리자 (System)
매개 변수가 두 개이고 TResult 매개 변수에 지정된 형식의 값을 반환하는 메서드를 캡슐화합니다.
learn.microsoft.com
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
public App()
{
//Func 대리자 변수 정의
//이 경우, 앞에 2개는 매개변수, 마지막 한개는 Sum함수 앞에 있는 형식
Func<int,int ,int> func;
//대리자 인스턴스화 (메서드 연결)
func = (a, b) =>
{
return a + b;
};
//대리자 사용
int sum = func(1, 2);
Console.WriteLine(sum);
}
int Sum(int a,int b)
{
return a + b;
}
}
}
Action 사용 callback(람다도 사용)
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
public App()
{
//대리자 초기화(대리자 인스턴스화 / 메서드연결)
Action moveComplete = () =>{
Console.WriteLine("영웅 이동완료");
};
Hero hero = new Hero();
hero.Move(moveComplete); //대리자 인스턴스를 인수로 전달
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnDotnet
{
public class Hero
{
public Hero()
{
Console.WriteLine("영웅이 생성되었습니다");
}
public void Move(Action callback)
{
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동완료");
callback();
}
}
}
--------------------다른 방식 구현-----------------------------
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
public App()
{
Hero hero = new Hero();
hero.moveComplete = () => {
Console.WriteLine("영웅이 이동완료 했습니다");
};
hero.Move();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnDotnet
{
public class Hero
{
//멤버 변수
public Action moveComplete; //대리자 변수 정의
//생성자
public Hero()
{
Console.WriteLine("영웅이 생성되었습니다");
}
public void Move()
{
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동완료");
this.moveComplete();
}
}
}
------------------------또 다른 방식 구현------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
public App()
{
Hero hero = new Hero();
hero.Move(() => {
Console.WriteLine("영웅이 이동완료 했습니다");
});
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnDotnet
{
public class Hero
{
//생성자
public Hero()
{
Console.WriteLine("영웅이 생성되었습니다");
}
public void Move(Action callback)
{
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동중.....");
Console.WriteLine("이동완료");
callback();
}
}
}
싱글톤 활용 Action 대리자
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnDotnet
{
public class DataManager
{
//멤버 변수
public Action loadComplete;
public static readonly DataManager instance = new DataManager();
//생성자
private DataManager()
{
}
public void LoadDatas()
{
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
this.loadComplete();
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
public App()
{
DataManager.instance.loadComplete = () => {
Console.WriteLine("데이터 로드 완료!");
};
DataManager.instance.LoadDatas();
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
public App()
{
Action loadComplete = () =>
{
Console.WriteLine("데이터 로드 완료!");
};
DataManager.instance.LoadDatas(loadComplete);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnDotnet
{
public class DataManager
{
//멤버 변수
//public Action loadComplete;
public static readonly DataManager instance = new DataManager();
//생성자
private DataManager()
{
}
public void LoadDatas(Action callback)
{
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
//this.loadComplete();
callback();
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
//using 지시문을 사용하면 네임스페이스에 정의된 형식을 해당 형식의 정규화된 네임스페이스를 지정하지 않고도 사용할 수 있습니다.
namespace LearnDotnet
{
//형식 정의
public class App
{
public App()
{
DataManager.instance.LoadDatas( () =>{
Console.WriteLine("데이터 로드 완료!");
});
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnDotnet
{
public class DataManager
{
//멤버 변수
//public Action loadComplete;
public static readonly DataManager instance = new DataManager();
//생성자
private DataManager()
{
}
public void LoadDatas(Action callback)
{
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
Console.WriteLine("데이터 로드중");
//this.loadComplete();
callback();
}
}
}