EasyCastleUNITY

대리자, 람다, Action 대리자와 Func 대리자 본문

개인 필기

대리자, 람다, Action 대리자와 Func 대리자

EasyCastleT 2023. 7. 27. 12:22

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();
        }
    }
}

'개인 필기' 카테고리의 다른 글

[과제] 동기와 비동기  (0) 2023.08.14
Unity Animation  (0) 2023.08.02
Unity Rigidbody | Collider | AddForce  (0) 2023.08.02
유니티 모바일 빌드 해상도 지정  (0) 2023.08.01
멀티캐스트 대리자 예시  (0) 2023.07.27