posted by 방랑군 2012. 1. 17. 20:56

출처 :  http://blog.naver.com/PostView.nhn?blogId=rintiantta&logNo=40115460090&categoryNo=59&viewDate=&currentPage=2&listtype=0&from=postList&userTopListOpen=true&userTopListCount=5&userTopListManageOpen=false&userTopListCurrentPage=2


어쨌건, 시작합니다. ㅎㅎ

프로젝트를 만들어주세요 ㅇㅅㅇ .. !
 


 

아래가 람다입니다. ㅇㅅㅇ

"헐킈, 먼가요 저게 ?"

『=>』요게 들어가면 람다입니다. 

 

『간단하게 x 라는 인수를 x*x 로 리턴한다는 뜻입니다.』

 

 

실행 한번 해보죠 ㅎㅎ

 

 

100 이 출력 되는 것을 볼 수 있습니다.

 

 

지금.. 제 생각에는..

"아놔, 리턴도 안 했는데, 뭐 위의 결과가 뜹니까?!" 하시는 분이 있을텐데요.

 

아래와 같이 return 을 써주셔도 됩니다 .ㅎㅎ

간단하게 X => Y 로 되어있는 람다식에서는 X 가 파라메터, Y 가 리턴값이 됩니다. >_<

 

 

아래와 같이 여러개를 넣을 수도 있지요 >_<

 

 

결과입니다. ㅎㅎ

 

 

근데 만약 파라메터가 2개라면... >_<

 

 

아래와 같이 해주시면 됩니다 .ㅇㅅㅇ...

무지 짧죠 ?

 

『귀차니즘의 역사』라고 말한 이유가 이것입니다.

점점점점점 짧아지죠... ㅎㅎ

 

 

그럼 이걸 어디다 쓰는지는 봐야죠 ㅇㅅㅇ...

그리고, 가끔 『=>』이게 나오면 "허걱... 이건 머임.." 하고 놀라시는 분이 있으시니, 조금 활용해보도록합시다. ㅎㅎ

 

우선 리스트에 Where 이라는 메서드가 있습니다.

조건에 맞는 녀석들을 뽑아서 다시 배열로 만들어주시는 분입니다.

 

보시면 파라메터로 Func<string, bool> predicate 를 달라고 하는데요.

뭔 개소리일까요 ㅇㅅㅇ ....

<string, bool> 의 뜻은 대충 『string을 박으면 bool 로 나오는 녀석』이라는 뜻입니다.

 

여기에, 리턴값이 bool 이고 파라메터가 string 인 메서드의 이름을 넣으셔도 됩니다.

근데, 길죠 ㅇㅅㅇ... 귀찮구 >_<

 

 

아래와 같이 람다식을 넣었습니다.

data 가 'A' 라는 글자를 가지고 있으면 true 를 리턴하게 되는 식입니다.

"아니, 왜 true 를 리턴하죠 ?!"

『Contains() 메서드는 맞으면 True 를 리턴하니까요 ㅇㅅㅇ』

 

자, 무지 짧아졌죠?

메소드 만들기는 『귀찮』으니까요 ... !

 

 

출력하시면 『1』이 나오겠지요 ~_~ ?

음... 결과 스크린샷을 찍었는데.... 없어졌네엥.. ;ㅁ;

 

 

어쨌건, 이번에는 MSDN 에 나오는 예제를 봅시다.

아래와 같이 썼어요.

 

Count() 메서드의 두번째 오버로딩 되는 녀석입니다.

위와 마찬가지로 해석하면요.

『int 를 박으면 bool 이 나오는 함수를 주렴 >_<』 이라는 뜻입니다.  

 

 

메서드 만들기는 귀찮죠 ... ?

아래와 같이 람다식을 박으시면 됩니다. ㅇㅅㅇ...

 

 

람다식은 일단 연습해보는 것이 제일 좋습니다. ㅇㅅㅇ

많은 연습이 제일 중요하죠.

연습하면, 메소드를 만들어야하는 귀찮은 녀석들을 위와 같이 간단간단 20글자 내외로 끝낼 수 있습니다.

 

자, 그럼 ㅇㅅㅇ ...

C# Basic 강의 종강입니다. ㅎㅎ

괜히 마지막을 Delegate 으로 잡아서 끝을 못 내드리고 똥 안 닦고 나온 기분을 연출시켜드려 죄송합니다. ;ㅁ;

딜리게이트는 Windows Forms 강의에서나 다시 보실 수 있게 될겁니다. ;ㅁ;

 

끝 ㅎㅎ ... !

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

TCP/IP Socket with C#  (0) 2012.01.18
델리게이트 선언뒤에 할당  (0) 2012.01.18
C# 람다식  (0) 2012.01.17
람다식(Lambda Expression)  (0) 2012.01.17
매소드를 인수로 넘기기..  (0) 2012.01.17
posted by 방랑군 2012. 1. 17. 19:59

출처 : http://blog.naver.com/pray44u?Redirect=Log&logNo=20100066352

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace pLambdaLinQ

{

class cLambda

{

delegate int delObj();

delegate int delObjPara1(int x);

delegate int delObjPara2(int x, int y);

static public int RtnMethod(int pInt)

{

return ++pInt;

}

static public void CallMethod()

{

/* 0. 간단한 람다식 */

/* 0.1. 람다식에서 메서드 호출 */

int x=10, y=20;

delObj doObj= () => { return RtnMethod(x); };

int i = doObj();

Console.WriteLine("(x, y) => return x + y; : {0}", i);

/* 0.2. 람다식에서 메서드 만들기 */

doObj = () => { return x + y; };

Console.WriteLine("return x + y : {0}", doObj());

/* 0.3. 람다식에서 매개변수 1개 있는 메서드 만들기 */

delObjPara1 dopObj1;

dopObj1 = (pX) => { return ++pX; };

Console.WriteLine("return ++pX : {0}", dopObj1(4));

/* 0.4. 람다식에서 매개변수 2개 있는 메서드 만들기 */

delObjPara2 dopObj2;

dopObj2 = (pX, pY) => { return pX + pY; };

Console.WriteLine("return pX + pY : {0}", dopObj2(2, 8));

/* 0.5. 람다식 정의 형식

* 1. 델리게이트 선언 : 매개변수 목록·반환데이터타입이 람다식과 일치

* delegate 반환데이터타입 델리게이트이름(매개변수목록);

* 2. 람다식을 델리게이트 변수에 할당

* 델리게이트이름 변수이름 = (매개변수목록) => {메서드의 body}

*

* 0.6. 람다식 사용

* 변수이름(매개변수목록)

*/

}

}

}

[출처] C# 람다식|작성자

 

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

델리게이트 선언뒤에 할당  (0) 2012.01.18
Delegate(5) : 람다식  (0) 2012.01.17
람다식(Lambda Expression)  (0) 2012.01.17
매소드를 인수로 넘기기..  (0) 2012.01.17
InvokeRequired  (0) 2012.01.17
posted by 방랑군 2012. 1. 17. 19:55

출처 :  http://www.csharpstudy.com/CSharp/CSharp-lambda.aspx 

C# 3.0부터 지원하는 => 연산자는 C#에서 람다 식(Lambda Expression)을 표현할 때 사용한다. 람다 식은 무명 메서드와 비슷하게 무명 함수(anonymous function)를 표현하는데 사용된다. 람다 식은 아래와 같이 입력 파라미터(0개 ~ N개)를 => 연산자 왼쪽에, 실행 문장들을 오른쪽에 둔다.

람다 Synyax : (입력 파라미터) => { 문장블럭 };

 

예를 들어 하나의 문자열을 받아 들여 메시지 박스를 띄운다면 다음과 같이 간단히 쓸 수 있다.

str => { MessageBox.Show(str); }

입력 파라미터는 하나도 없는 경우부터 여러 개 있는 경우가 있다. 다음 예는 파라미터가 없는 케이스 부터 두개 있는 케이스까지 보여준다. 마지막 예는 입력 파라미터의 타입이 애매한 경우 이를 써줄 수 있음을 보여준다. 일반적으로 입력타입은 컴파일러가 알아서 찾아낸다.

() => Write("No");
(p) => Write(p);
(s, e) => Write(e);
(string s, int i) => Write(s, i);

Lambda Expression을 이용하면 이전 페이지에 소개한 delegate/무명 메서드를 더 간략히 표현할 수 있다. 예를 들어 다음과 같은 Click 이벤트는 이벤트 핸들러 메서드인 button1_Click를 가리키고 있다. 그래서 메서드 button1_Click은 해당 클래스내 어딘가에 정의되어 있어야 한다.

this.button1.Click += new System.EventHandler(button1_Click);

private void button1_Click(object sender, EventArgs e)
{
   ((Button)sender).BackColor = Color.Red;
}


new System.EventHandler(button1_Click)은 간단히 button1_Click 메서드명만 사용하여 아래와 같이 줄일 수 있다.

this.button1.Click += button1_Click;

이를 좀더 간단하려면 아래와 같이 무명 메서드(Anonymous Method)를 써서 표현할 수 있다.

this.button1.Click += delegate(object sender, EventArgs e)
{
   ((Button)sender).BackColor = Color.Red;
};

그리고 람다 식을 사용하면 이를 더 간단히 다음과 같이 바꿀 수 있다. 람다 식의 오른쪽 실행 블럭이 한 문장일 때는 { } 괄호를 생략할 수 있다. 아래 식은 무명 메서드를 쉽게 람다 식으로 변경한 간단한 예이다.
this.button1.Click += (sender, e) => ((Button)sender).BackColor = Color.Red;

람다 식(Lambda Expression)은 .NET 여러 곳에서 사용되지만 특히 LINQ (Language Integrated Query) 에서 많이 사용된다. LINQ는 별도의 주제이지만 아래는 람다식이 LINQ의 Where 쿼리에서 사용되는 간단한 예이다.
var proj = db.Projects.Where(p => p.Name == strName);
 

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

Delegate(5) : 람다식  (0) 2012.01.17
C# 람다식  (0) 2012.01.17
매소드를 인수로 넘기기..  (0) 2012.01.17
InvokeRequired  (0) 2012.01.17
InvokeRequired & Cross Thread 처리방법  (0) 2012.01.17
posted by 방랑군 2012. 1. 17. 19:35

출처 :  http://rintiantta.blog.me/40121658531 

시작합시다. ㅎㅎ
프로젝트를 만들어주세요 ㅇㅅㅇ ...

 


 

우선 Delegate 만드는 방법입니다.

그냥 아래와 같이 일반 필드 만드는 듯이 하신 뒤에 뒤에 그냥 메소드를 박아주시면 됩니다. ㅎㅎ



 

그리고 아래와 같이 메소드를 넣어주시면 됩니다. ~_~...

정말 뭐에 쓰는지는 모르겠지만, 일단 이해는 쉽죠 ... ?

 

int FirstDelegate(int x, int y) 이니,

리턴타입이 int 고, 파라메터가 int 2개인 메소드를 대입할 수 있는거랍니다. ㅎ

 

 

아래와 같이 하시면요 ㅇㅅㅇ ...

뭐, 쓸 수 있는 겁니다.

 

fd = Method 니까, 10 + 20, 30을 리턴하겠지요.



 

그리고 아래와 같이 메소드를 인수로 넘길 수도 있는 것이지요 ~_~...

 

 

아래와 같이 보시면 메소드의 형태를 볼 수 있는데요.

 

 

아래와 같이 형태를 볼 수 있습니다.

 

 

보신 뒤 나올 예상 반응 100 %

"그래서요 ... ?"

『....인터페이스의 기본적인 것을 Basic 강의에서 다루구요.』

『활용방법 자체는 콘솔에서 볼 수 없습니다. 우선, 인터페이스를 약간 업 시켜서 이벤트는 중급 강의에서 볼겁니다 ~_~ ㅎㅎ』

어쨌거나 끄읏 ~
 

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

C# 람다식  (0) 2012.01.17
람다식(Lambda Expression)  (0) 2012.01.17
InvokeRequired  (0) 2012.01.17
InvokeRequired & Cross Thread 처리방법  (0) 2012.01.17
인터페이스를 상속한 자신을 파라미터로 호출한 경우.  (0) 2012.01.17
posted by 방랑군 2012. 1. 17. 04:45

출처 :  http://pillblog.tistory.com/entry/CrossThread 

간혹 쓰래드 안에서 혹은! 동적으로 만들어진 컨트롤이 다른 윈도우 컨트롤의 모양(레이아웃)을 건드리려 한다면!!

다음과 같은 에러가 발생한다. 

 System.UnauthorizedAccessException: Invalid cross-thread access

혹은

Cross-thread operation not valid: blah blah blah :p

그럴땐 어찌하는냐!! 

Delegate를 써야한다.

윈도우 컨트롤에게 InvokeRequired라는 걸로 이렇게 물어본다.

"내가 니 몸뚱이 색깔 좀 바꿀려는데 좀 기다릴까?"

그러면 InvokeRequired가  true/false로 대답해 줄 것이다. ㅋㅋ

허나 질문에 주의하라! true면 기다리라는 것이므로 Delegate로 하나 더 날려준다.

그리고 false가 나오면 바꾸면 된다.

InvokeRequired는 바꾸려는 컨트롤의 것을 사용해야한다. 

아래의 경우 패널을 바꾸기 위해 사용한 것. 그러므로 InvokeRequired는 패널에게 물어본다. 

코드는 아래와 같다.

        private Command PopupInvoke(Popup popup, ScreenPanel pnl)
        {
            if (pnl.InvokeRequired)
            {
                InvokeDelegate<PopupScreenPanel> id = new InvokeDelegate<PopupScreenPanel>(PopupInvoke);
                pnl.Invoke(id, new object[]{popup, pnl});
            }
            else
            {
                popup.Size = pnl.Size;
                pnl.Location = new Point(0, 0);
                pnl.Parent = popup.pnlPopup;

                popup.ShowDialog();
            }
            return null;

        } 
posted by 방랑군 2012. 1. 17. 04:39


출처 :  http://sanbj.tistory.com/entry/CCross-Thread 

최근에 소켓프로그램을 개발하던 중에도 Cross Thread 문제를 겪었다.
서버에서 Thread을 생성하여 데이터 수신을 기다리고, 수신된 데이터의 내용을 RichTextBox에 출력하려는 작업중에 
Cross-thread operation not valid: Control 'rtb_console' accessed from a thread other than the thread it was created on. 
이러한 메세지를 내뿜고 뻗어버렸다.

이런 문제를 포스팅하기 위해 샘플소스를 작성하였다.

에러가 발생하는 소스
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace MyServer
{
    public partial class Form1 : Form
    {
        private Thread _thread;
        private RichTextBox rtb_console;

        public Form1()
        {
            InitializeComponent();

            _thread = new Thread(new ThreadStart(ThreadProc));
            _thread.Start();
        }

        private void ThreadProc()
        {
int count = 0;
            while (true)
            {
                SetTextBox(count,"hello");
    count++;
            }
        }
        
        private void SetTextBox(int count, String str)
        {
             rtb_console.Text = count.ToString() +"번째" + str;
         }
    }
}


프로그램은 기본적으로 하나의 Thread(MainThread라 하자)로 시작되고, 그 Thread 내에서 UI를 화면에 그리는 메세지와 이벤트도 처리하게 된다. 하지만 사용자가 추가로 생성한 Thread는 이와 별개에 작업을 하고 있기 때문에 MainThread에 의해 그려진 UI영역(컨트롤)등을 직접 접근하게 되면 MainThread입장에서는 UI관련 메세지와 이벤트를 처리하고 있는데 다른 Thread가 방해를 하는 셈이다. 이런 상황을 Cross Thread라 한다.

위에 소스를 보게되면 프로그램이 실행되면서 시작하는 Thread에서 Form1 객체를 생성하였고, Form1객체가 RichTextBox컨트롤을 생성하였다. 예외를 발생시키기위해 임의로 Thread하나를 생성하였고, 그 Thread 안에서 RichTextBox컨트롤에 직접 접근하였다.
역시 밑줄 친 라인에서 예외를 발생시킨다.

이문제를 해결하는 방법은 Invoke 메소드를 이용하는 것이다.
MSDN에서는 Invoke를 다음과 같이 설명하고 있다.

WPF에서는 DispatcherObject를 만든 스레드만 해당 개체에 액세스할 수 있습니다. 예를 들어 기본 UI 스레드에서 분리된 백그라운드 스레드는 UI 스레드에서 작성된 Button의 콘텐츠를 업데이트할 수 없습니다. 백그라운드 스레드가 Button의 Content 속성에 액세스하려면 백그라운드 스레드에서 UI 스레드에 연결된 Dispatcher에 작업을 위임해야 합니다. 이 작업은 Invoke 또는 BeginInvoke를 사용하여 수행할 수 있습니다. Invoke는 동기적이고 BeginInvoke는 비동기적입니다. 작업은 지정된 DispatcherPriority에서 Dispatcher의 이벤트 큐에 추가됩니다. 

다른 Thread에서는 UIThread(MainThread)에 접근할 수 없기 때문에 
UIThread의 Invoke메소드를 이용하여,
 다른 Thread에서 호출할 메소드를 delegate로 
정의하여 넘겨줘야 한다. 
호출될 메소드의 파라메터가 있다면 이는 object로 넘겨주면된다.
이렇게 해주게 되면 MainThread에게 너 할일 다하고,
이것도 좀 해줘라는 식으로 전달되게 된다.


수정된 소스
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace MyServer
{
    public partial class Form1 : Form
    {
        private Thread _thread;
        private RichTextBox rtb_console;
        private delegate void SetTextBoxCallback(int count, String str);

        public Form1()
        {
            InitializeComponent();

            _thread = new Thread(new ThreadStart(ThreadProc));
            _thread.Start();
        }

        private void ThreadProc()
        {
            int count = 0;
            while (true)
            {
                SetTextBox(count,"hello");
                count++;
            }
        }

        private void SetTextBox(int count, String str)
        {
            if (this.rtb_console.InvokeRequired)
            {
                SetTextBoxCallback setTextBoxCallback =                                           
                                                                      new  SetTextBoxCallback(SetTextBox);
                this.Invoke(setTextBoxCallback, new object[] { count, str });
            }

            else
            {
                rtb_console.Text = count.ToString() +"번째" + str;
            }
        }
    }
}

private delegate void SetTextBoxCallback(int count, String str);
추가 되었고, SetTextBox에서 InvokeRequired라는 속성을 사용하였다.

InvokeRequired는 다른 Thread로부터 호출되어 Invoke가 필요한 상태를 체크하여 true/false를 리턴한다. 따라서 Invoke가 필요한 상태일때는 Invoke메소드에 의해 호출될 SetTextBox를 delegate로 넘겨주면 된다.

위 소스에서 사실은 this.rtb_console.Invoke를 호출해야 하지만 this.Invoke로 호출하였는데, this.rtb_console(TextBox)이나 this(Form)나 MainThread의 영역이기 때문에 this.Invoke로도 같은 MainThread에게 위임하게 된다. 


posted by 방랑군 2012. 1. 17. 03:50
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;

namespace ConsoleApplication1
{

    public interface IMessengeSeverUI
    {
        void WriteMessage(string message);

        void UpdateClientCount(int count);
    }

    public class MessengServerUI : IMessengeSeverUI
    {

        #region IMessengeSeverUI 멤버

        public void WriteMessage(string message)
        {           
            Debug.Write(message);            
        }

        public void UpdateClientCount(int count)
        {            
            Debug.Write(count);            
        }

        #endregion
    }

    public interface IMessengerServer
    {
        bool Start(IMessengeSeverUI ui);

        bool Stop();
    }

    public class MessengerServer : IMessengerServer
    {
        private string m_ID="황승재";

        public string ID {
            get {
                return m_ID;
            }
        }
        #region IMessengerServer 멤버

        public bool Start(IMessengeSeverUI ui)
        {           
            ui.WriteMessage("IMessengeSeverUI 상속된 자신을 파라미터로 보낸 경우");
            return true;
        }

        public bool Stop()
        {           
            Debug.Write("Stop");
            return true;
        }

        #endregion
    }

    class Program
    {
        static void Main(string[] args)
        {

            // 1
            IMessengeSeverUI m_ui = new MessengServerUI();
            m_ui.WriteMessage("인터페이스가 하위 상속된 클레스 함수 호출.");
           
            // 2
            (new TestClass()).Click();
        }
    }

    class TestClass : IMessengeSeverUI
    {
        private IMessengerServer m_server = null;

        public void Click()
        {
            m_server = new MessengerServer();

            m_server.Start(this);
        }

        #region IMessengeSeverUI 멤버

        public void WriteMessage(string message)
        {
            //throw new NotImplementedException();
            Debug.Write(message);
        }

        public void UpdateClientCount(int count)
        {
            //throw new NotImplementedException();
            Debug.Write(count);
        }

        #endregion
    }
}

posted by 방랑군 2012. 1. 17. 03:23
    public interface IMessengeSeverUI
    {
        void WriteMessage(string message);

        void UpdateClientCount(int count);
    }

    public class MessengServerUI : IMessengeSeverUI
    {

        #region IMessengeSeverUI 멤버

        public void WriteMessage(string message)
        {
           
            Debug.Write(message);            
        }

        public void UpdateClientCount(int count)
        {
           
            Debug.Write(count);            
        }

        #endregion
    }

static void Main(string[] args)
        {

            IMessengeSeverUI m_ui = new MessengServerUI();

            m_ui.WriteMessage("인터페이스가 하위 상속된 클레스 함수 호출.");
        }

결과 :  인터페이스가 하위 상속된 클레스 함수 호출.
posted by 방랑군 2012. 1. 17. 02:54
using System;

using System.Threading;

namespace VTFramework.ThreadEx
{
/// <summary>
/// vS_Thread에 대한 요약 설명입니다.
/// 
///  쓰레드에 인수를 넘기는 방법.
/// 
/// - Example
/// string strMsgInfo = "전달 값";
/// Thread td = vCS_ThreadEx.CreateThread(new vCS_ThreadEx.dg_ThreadProc(ThreadProc),strMsgInfo);
/// td.Start();
/// 
/// private void ThreadProc(object[] p) 
/// {}
/// </summary>
public class vCS_ThreadEx
{
public vCS_ThreadEx()
{
//
// TODO: 여기에 생성자 논리를 추가합니다.
//
}

public delegate void dg_ThreadProc(object[] o); 

private class ParamProc 

public object[] param; 
public dg_ThreadProc proc; 

public void work() 
proc(param);

public void work(object objValue) 
proc(param);
}   

public static Thread CreateThread(dg_ThreadProc proc, params object[] arg) 
ParamProc pp = new ParamProc(); 
pp.param = arg; 
pp.proc = proc; 
Thread t = new Thread(new ThreadStart(pp.work));
return t; 
}
}

posted by 방랑군 2012. 1. 17. 02:52

그것은 C# 프로그래밍의 첫걸음을 내디면서 만난 첫번째 난관이었다.

단지 쓰레드를 생성하고 그 안에서 폼에 붙어있는 레이블 컨트롤의 텍스트 속성만 바꿔주려 했을 뿐이었는데, 난데 없이 튀어나오는 예외메세지에 당황하지 않을 수 없었다. 원인을 찾아보니,

C# 스레드에선 다른 스레드의 컨트롤을 건드는 일은 하지 말아야 한다는 것이었다.

이래서 더더욱 난 C/C++이 좋을 수 밖에. C#은 너무 딱딱하다. 깐깐하다.

그럼 이런 상황을 가능하도록 만들려면? invoke를 통해 교차쓰레드접근을 우회하면 된다고 하는데,

무슨말인지, 나더러 어쩌라는건지 더더욱 당황스러워지고...인터넷 뒤져서 다른분들의 소스도 좀 찾아보고, 책도 보고, MSDN도 뒤져보고 나니 이렇게 하면 되는구나 하는 감이 오기는 하더라.

스포츠 뉴스에 보니, 퍼거슨이 나니를 팔일은 없을거라고 하던데...

어찌됬건간에 본론으로 돌아와서,

위의 예외창이 뜨는 경우의 예를 보면 다음과 같다.

public void threadfunc()

{

m_mainform.button1.Text = i.ToString();

}

보시는데로, 이 함수는 메인폼 버튼의 텍스트를 설정해주는 코드다.

디버그모드로 빌드할 경우, 위 함수를 쓰레드로 돌리면 여지없이 예외박스가 출현해 주신다. 릴리즈 모드로 돌리면 잘 돌아가는것 처럼 보이는데 영 찜찜하다. 나중에 문제가 될지도 모르겠고, 비록 돌긴 돌아도 하지 말라는 짓이니 만큼 예외박스를 없애야 속이 편할 것 같다.

예외를 발생시키는 위 함수를 다음과 같이 고쳐보면,

public void threadfunc()

{

m_mainform.Invoke(new MethodInvoker(delegate()
{
m_mainform.button2.Text = i_1.ToString();
}));

}

어라, 잘 돈다. 쓰레드에서 버튼 텍스트를 직접 변경하는게 아니라, 폼의 Invoke 메소드를 통해서 버튼의 텍스트를 변경한다.

그리고 Invoke메소드를 사용하기 위해선 delegate를 인자로 제공해 주어야 한다. 위 예에선 MethodInvoker delegate가 제공되었는데, Microsoft.JScript 네임스페이스 안의 MethodInvoker 클래스와 혼동하지 말아야 겠다.

MethodInvoker delegate는 인자로 제공된 메소드를 실행하는 delegate를 나타내준다.

여기서 MethodInvoker에 제공된 인자는 바로,

"delegate(){m_mainform.button2.Text = i_1.ToString();}" 요놈이다.

메소드가 통째로 들어가 있다.

보기엔 안좋지만, 결국엔 폼의 Invoke메소드에 delegate를 인자로 제공하여 원하던 것을 할 수 있게 되었다.

한가지 불편한 점은 MethodInvoker delegate는 오로지 파라미터도 없고 리턴값도 없는 메소드만을 인자로 사용할 수 있다는 점인데, delegate 메소드에 파라미터를 넘겨야 할 경우엔 어떡해야 하나?

머리좀 굴려보면 굳이 파라미터가 필요 없더라도 같은 효과를 얻을 수 있을 것이고,

꼭 파라미터를 넘기고 싶다면 넘기면 된다. 어떻게?

다음과 같이 매개변수를 받은 함수의 타입의 delegate를 선언해준다.

delegate void SetObjectText_invoke3(int i);

이 예에선 int형의 변수를 파라미터로 취하는 함수타입으로 delegate를 선언했다.

C에서의 함수포인터의 개념과 비슷해보인다.

타입을 선언하였으면 그 타입으로 변수를 정의한다.

SetObjectText_invoke3 MI_SetText;

그리고, MI_SetText에 우리가 실제로 사용할 함수를 대입해넣는다.

MI_SetText = settext_invoke3;

settext_invoke3함수는 아래처럼 정의되어있다.

public void settext_invoke3(int i)

{

m_mainform.button4.Text = i.ToString();

}

역시, 매개변수로 받는 i를 이용해 버튼컨트롤의 Text를 바꾸는 코드다.

이제 쓰레드 안에서 다음처럼 사용하면 된다.

m_mainform.Invoke(MI_SetText, i);

샘플첨부.

TEST_Delegate_Winform.zip

posted by 방랑군 2012. 1. 17. 02:25

delegate 리턴타입 델리게이트명(파라미터);

 

델리게이트는 자신에게 연결된 함수를 대신 실행시켜주는 역할을 하는 일종의 함수 포인터이다.
즉 자신에게 할당된 함수를 대신 실행시켜준다.

 

델리게이트와 연결된 메서드의 목록을 확인할 때에는 GetInvocationList 메서드를 이용한다.


ex) foreach (var delegate in XXXXDelegate.GetInvocationList()) { // ... }

 

델리게이트는 익명 메서드, 람다 메서드와 궁합이 잘 맞는다.
익명 메서드, 람다 메서드는 표현식을 간결하게, 인라인의 형태로 가져감으로써 코드가 축약되고
경우에 따라 가독성이 향상된다.

 

1. 익명 메서드 (이름이 없는 메서드)
델리게이트에 의해 호출되는 함수가 단순한 작업을 수행하는 '짧은' 메서드라면 굳이 새롭게 메서드의 이름을 정의하고 구현하는 것보다 익명 메서드를 이용하는 것이 낫다.

 

ex)
delegate void SampleDelegate(string message);

SampleDelegate sample = delegate(string message)
{
 Console.WriteLine(message);
};

sample("Hello, World");

 

2. 람다 메서드 (익명 메서드의 소집합)
람다식의 특징은 람다 연산자 '=>'에 있다.

1번의 예제 내용이 다음과 같이 축약됩니다.


ex)
SampleDelegate sample = (string message) => Console.WriteLine(message);

Delegate(대리자) 

 1] 함수의 기능을 대신해 주는 대리자 역할을 한다.

 2] 여기서 대리자라 하면 자신에게 전달된 함수를 대신해 준다고 보면..

 3] Delegate를 선언하려면 함수의 시그너쳐를 일치

  ==> 함수의 매개변수와 데이터 타입.....

 4] 이벤트는 델리게이트 기반으로 만들어 졌다.

   Ex) this.버튼.click += .....();

Delegate 선언

 delegate 리턴타입 델리게이트명(파라미터타입 변수);

Delegate 생성 및 호출

 델리게이트명 델리변수명 = new 델리게이트명(생성함수명);


 public 리턴타입 생성함수명(파라미터타입 변수)

 {

   // 코드

 }

Delegate 간단 예제_1

 delegate void deleTest(string strParam);

 static void Main(string[] args)
 {
    deleTest testDele_1 = new deleTest(dely);
    deleTest testDele_2 = new deleTest(dely);

    testDele_1("도망노비 테스트_1");
    testDele_2("이게 델린가여??");
 }

 public static void dely(string strParam)
 {
    Console.WriteLine(strParam);
 }

Delegate 간단 예제_2

 delegate void deleTest(string strParam);

 class Program
 {
    public static void Main()
    {
        TestDele classDele = new TestDele();
        deleTest dele_1 = new deleTest(classDele.DeleTest_1);
        dele_1("11");

        deleTest dele_2 = new deleTest(classDele.DeleTest_2);
        dele_2("11");
    }
 }

 class TestDele
 {
   public void DeleTest_1(string strParam)
    {
        Console.Write("Static_TEST ==> ");
        Console.WriteLine(strParam);
    }
    public void DeleTest_2(string strParam)
    {
        Console.Write("TEST ==> ");
        Console.WriteLine(strParam);
    }
 }


[출처] [C#] Delegate|작성자 에스이오케이