Get it on Google Play


Wm뮤 :: C# Delegate와 IEnumerator

블로그 이미지
가끔 그림그리거나 3D모델링하거나
취미로 로봇만드는
퇴직한 전자과 게임프로그래머
2020.3.48f1 , 2022.3.6f1 주로 사용
모카쨩
@Ahzkwid

Recent Comment

Archive


2021. 10. 11. 19:05 Unity/C#

Delegate = 대리자
말그대로 대신 실행시켜주는것
invoke나 event를 쓰기위해선 필수

 

그외에도 비동기 계열들을 동기 계열처럼 쓸 수 있게 해준다


예제1

namespace namespace1
{
    public delegate void delegate_sender(string text_buff);
    public static class class1
    {

        void Main()
        {
            class2 cl = new class2(); //클래스 생성
            cl.delegate_handle = new delegate_sender(text_set); //대리시킬 함수 명시
        }
        set_text(string text)
        {
            messagebox.show(text);
        }
    }
    class class2 //이벤트를 실행할 클래스2
    {
        public static delegate_sender delegate_handle;
        void main()
        {
            delegate_handle("test");//델리게이트 동작
        }
    }
}

 

 

 

 

 

 

이벤트

용도: 이벤트가 발생하면 이벤트 리스너에 등록된 곳에서 모두 동작을 실시합니다

namespace namespace1
{
    public delegate void delegate_sender(string text_buff);
    public static class class1
    {

        void Main()
        {
            class2 cl = new class2(); //클래스 생성
            cl.event_handle += new delegate_sender(show_text); //이벤트 등록
        }
        show_text(string text)
        {
            messagebox.show(text);
        }
    }
    class class2 //이벤트를 실행할 클래스2
    {
        public event delegate_sender event_handle; //이벤트 리스너 생성
        void main()
        {
            event_handle("test");//이벤트 동작
        }
        public void CallEvent(string text)//이벤트 핸들은 반드시 해당 클래스에서 호출해야 하기 때문에 외부에서 호출시 이런식으로 호출
        {
            event_handle("test");//이벤트 동작
        }
    }
}

 

 

 

 

Invoke함수

존나 옛날에 내가 다 정리해놨었네;

요새 프로그래밍 다시 시작하면서 복습중이다

Invoke(Delegate) 
//컨트롤의 내부 창 핸들이 있는 스레드에서 지정된 대리자를 실행합니다.

Invoke(Delegate, Object[]) 
//컨트롤의 내부 창 핸들이 있는 스레드에서 특정 인수 목록을 사용하여 지정된 대리자를 실행합니다.
private void SetText(string text)
{
    // InvokeRequired required compares the thread ID of the
    // calling thread to the thread ID of the creating thread.
    // If these threads are different, it returns true.
    if (this.textBox_log.InvokeRequired)
    {
        //delegate_sender d = new delegate_sender (SetText);
        //this.Invoke(new delegate_sender (SetText), new object[] { text });
        //this.Invoke(new Action(delegate () {할일 }));
        //string _return ="";
        //this.Invoke(new Action(delegate () { _return = this.textBox.Text; }));
        this.Invoke(new delegate_sender(SetText), text);
    }
    else
    {
        this.textBox.Text = text;
    }
}

 

 

이건 윈폼예제

간단한 요약

멀티스레드에서 가장 문제가 되는 클립보드 접근에 대한것

핸들이 static이므로 그냥 막 쓸수 있다

    public delegate void de_set_clip(string text); //입력예제
    public delegate string de_get_clip(); //출력예제
    public partial class Form1: Form
    {
        public void set_clip(string input)  //입력함수
        {
            this.Invoke(new Action(delegate () {
                Clipboard.SetText(input);
            }));
        }
        public string get_clip()  //출력함수
        {
            String _return ="";
            this.Invoke(new Action(delegate () {
                _return=Clipboard.GetText();
            }));
            return _return;
        }
        public Form1() //사용할 폼
        {
            clip.de_set_clip_handle = new de_set_clip(set_clip);
            clip.de_get_clip_handle = new de_get_clip(get_clip);

            InitializeComponent();
}

    public static class clip
    {
        public static de_set_clip de_set_clip_handle; //이걸 다른 폼에서 사용
        public static de_get_clip de_get_clip_handle;
    }
}

 

 

 

 

존나 옛날에 짠거들이라 리메이크 해야할듯

 

 

 

 

 

 

 

 

 

 

 

delegate기반 계열로 Action이 있다

위쪽이 이벤트 기반이라면 이쪽은 비동기 리턴에 사용

 

 

비동기 리턴 예제

    public void Login() //외부에서 리턴안쓰고 호출할때 사용
    {
        Login(success=> { });
    }
    public void Login(System.Action<bool> successCallback)
    {
        if (로그인 하는데 성공)
        {
            successCallback.Invoke(true);
        }
        else
        {
            successCallback.Invoke(false);
        }
    }
    public void Start()
    {
        Login(success =>
        {

            if (success)
            {
            	//성공했을경우 처리
            }
            else
            {
            	//실패했을경우 처리
            }

        });
    }

 

 

 

 

 

 

 

이벤트 핸들러 예제

    
    public event System.EventHandler StateChanged;
    public void OnStateChanged()
    {
        //sender는 누가 발생시켰는지, System.EventArgs.Empty는 리턴밸류를 할당하지 않겠다는 뜻
        StateChanged?.Invoke(sender:this, System.EventArgs.Empty);
        Debug.Log("상태가 전환됨");
    }
    public void Start()
    {
    	StateChanged+=OnStateChanged;
    }

 

 

 

 

 

 

 

 

유니티 전용 이벤트가 있다

유니티 이벤트 기능

public class CustomInteface
{


    [System.Serializable]
	public class Vector3Event : UnityEngine.Events.UnityEvent<Vector3> { }
	//public class VoidEvent : UnityEngine.Events.UnityEvent { }
    
    //public UnityEvent OnEvent; //void 타입
    public Vector3Event OnEvent;
    
    
    void Start()
    {
    	//함수를 붙일때
        OnEvent.AddListener (Draw);
    
    	//호출
        OnEvent.Invoke(transform.position);
    }

	//붙일함수
    void Draw(Vector3 pos)
    {
		Debug.Log ("pos:"+pos);
    }


}

 

 

MonoBehaviour.Invoke

특정 함수를 0.4초 딜레이후에 호출

코루틴과 달리 오프된 상태에서도 사용가능해서 트리거 만들때 유용해보인다

유니티 함수도 쓸수있다

Invoke(nameof(Logout),0.4f);

 

위랑 같은데 일정시간마다 반복함

커스텀 업데이트만들때 유용해보이나 중단점을 잘 맞춰야 할것이다

InvokeRepeating(nameof(methodName),delay : 3,repeatTime : 1);



CancelInvoke(nameof(methodName)); //해당 Invoke메소드를 중단
CancelInvoke(); //모든 Invoke메소드를 중단

 

 

 

 

-코루틴 계열들

IEnumerator = 열거자

코루틴은 IEnumerator기반으로 동작함

 

코루틴이 동작중인지 체크

    IEnumerator preCoroutine;
    void StartMusic()
    {
            if (preCoroutine != null)
            {
                StopCoroutine(preCoroutine);
            }
            preCoroutine = MusicEnd();
        Debug.Log("음악시작");
            StartCoroutine(preCoroutine);
    }
    IEnumerator MusicEnd()
    {
        yield return new WaitForSeconds(10f);
        Debug.Log("음악이 종료됨");
        preCoroutine =null;
    }

 

코루틴이 동작중인지 체크2

위 1번이 그냥 일반상황에서 쓴다면

2번은 코루틴내의 코루틴을 동작시킬때 씀

v1

더보기

 

IEnumerator preReset;
void Reset()
{
    if ((preReset == null)||((preReset.Current.GetType()==typeof(int)) &&((int)preReset.Current == 0)))//Current의 타입검사도 필요함
    {
        preReset = ResetCo();
        StartCoroutine(preReset);
    }
}
IEnumerator ResetCo()
{
    yield return 0;//종료
}

 

 

v2

더보기

 

IEnumerator preReset;
void Reset()
{
    if ((preReset == null) || ((preReset.Current is int current) && (current == 0)))//Current의 타입검사도 필요함
    {
        preReset = ResetCo();
        StartCoroutine(preReset);
    }
}
IEnumerator ResetCo()
{
    yield return 0;//종료
}

 

 

v3 일반

IEnumerator preReset;
void Reset()
{
    if (preReset?.Current as string == "End")//Current의 타입검사도 필요함
    {
        preReset = ResetCo();
        StartCoroutine(preReset);
    }
}
IEnumerator ResetCo()
{
    yield return "End";//종료
}

 

 

v3 코루틴

이 버전의 강점은 지역변수만으로도 체크 가능하단것

IEnumerator RoutineAllAria()
{
    var preAria = aria;
    for (int i = 0; i < System.Enum.GetValues(typeof(Aria)).Length; i++)
    {
        var co = Routine((Aria)i);
        StartCoroutine(co);
        yield return new WaitUntil(()=>co?.Current as string == "end"); //Current의 타입검사도 필요함
    }
    aria = preAria;
}
IEnumerator Routine(Aria aria)
{
	//실행로직
    yield return "end";//종료
}

 

v3 리스트

스킬관리할때 썼음

    public void Skill(int index)
    {
        var delaySkillSpawn = DelaySkillSpawn(skillPrefab);
        StartCoroutine(delaySkillSpawn);
        delaySkillSpawns.Add(delaySkillSpawn);
        delaySkillSpawns = delaySkillSpawns.FindAll(x => (x?.Current as string == "End")==false);
    }
    public List<IEnumerator> delaySkillSpawns = new List<IEnumerator>();
    public void SkillCancel()
    {
        delaySkillSpawns = delaySkillSpawns.FindAll(x => (x?.Current as string == "End") == false);
        foreach (var delaySkillSpawn in delaySkillSpawns)
        {
            StopCoroutine(delaySkillSpawn);
        }
        delaySkillSpawns.Clear();
    }
    private IEnumerator DelaySkillSpawn(SkillSystem.SkillPrefab skillPrefab)
    {
        yield return new WaitForSeconds(skillPrefab.spawnDelay);
        if (hp<0)
        {
            yield return "End";//종료
            yield break; //반환하지않고 중단
        }
        
        
        //동작코드들
        
        
        yield return "End";//종료
    }

 

 

 

 

 

frame이 10 이상이 될때까지 대기

    IEnumerator Example()
    {
        yield return new WaitUntil(() => frame >= 10);
        Debug.Log("프레임이 10 이상임");
    }

 

비동기 함수가 끝날때까지 대기

v1

더보기
    IEnumerator LoadSpritesCo()
    {
        {
            var co = GetFolderToSpriteFilesCo(folderPath);
            StartCoroutine(co);
            yield return new WaitUntil(() => co.Current.GetType() == typeof(Sprite[]));
            sprites = (Sprite[])co.Current;
        }
    }

v2

    IEnumerator LoadSpritesCo()
    {
        {
            var co = GetFolderToSpriteFilesCo(folderPath);
            StartCoroutine(co);
            yield return new WaitUntil(() => co?.Current as Sprite[] != null);
            sprites = (Sprite[])co.Current;
        }
    }

 

IEnumerator 내부에서 코루틴 종료

IEnumerator SampleCo()
{
    Debug.Log("코루틴 실행중");
    yield break;
    Debug.Log("코루틴이 종료되어 실행할수 없는 문구");
}

 

 

IEnumerator 반환값 예제

    IEnumerator TestCo()
    {
        //반환값 null
        yield return new WaitForSeconds(10);

        //반환값 UnityEngine.WaitForSeconds

        yield return 0;

        //반환값 0

        yield break;

        //반환값 0
    }

 

 

변수가 변경될경우 이벤트 호출

    public IEnumerator IndexChengedChecker()
    {
        while (true)
        {
            var indexPrevious = index;
            yield return new WaitUntil(() => index != indexPrevious);


            //상태 변경됨
            //event.Invoke();
        }
    }

 

 

 

 

 

 

 

 

 

 

그외에 이것들을 쓴다는건 비동기계열을 다룬다는 소리인데

스레드나 태스크계열도 참조할 필요가 생긴다 (링크참조)

https://wmmu.tistory.com/entry/c-%EB%A9%80%ED%8B%B0%EC%8A%A4%EB%A0%88%EB%93%9C%ED%92%80-%EA%B8%B0%EB%B3%B8%EC%86%8C%EC%8A%A4

 

c# 멀티스레드 기본소스

c# 멀티스레드풀 기본소스 using System.Collections; public bool multi_threadpool_MC(float[,] img1f) { int img1wid = img1f.GetLength(0); // 기준 이미지 너비 int img1hei = img1f.GetLength(1); //기준..

wmmu.tistory.com

 

'Unity > C#' 카테고리의 다른 글

C# 시리얼  (0) 2021.10.11
c# 해쉬테이블  (0) 2021.09.13
자주쓰는 c# 소켓 통신 모음  (0) 2021.09.08
posted by 모카쨩

  • total
  • today
  • yesterday

Recent Post

저사양 유저용 블로그 진입