close

 

 image

加入 Form1_Load事件

image

   1: delegate int multiply(int x, int y);
   2: delegate int timestwo(int x);                    // [1] 新增一個叫做timestwo的delegate,其輸入個數 = 1, 輸出個數=1 
   3:  
   4: timestwo t = delegate(int x) { return 2 * x; };  // 定義一個timestwo變數t, 利用匿名方法初始化之 
   5: multiply m = delegate(int x, int y) { return x * y; };
   6: private void button2_Click(object sender, EventArgs e)
   7: {
   8:     MessageBox.Show(t(5).ToString());
   9:     MessageBox.Show( m(5, 6).ToString());
  10: }

[重點1]

常見匿名方法(Anonymous Methods)是將程式碼區塊(code block)當做委派(delegate)參數傳遞的一種方式

匿名方法:  delegate( arg1, arg2){ … }

 

以Button為例:

button物件.事件名稱 += delegate( 引數1, 引數2)           

{

   .............(code block)...........

}; 

下面為Click和MouseWheel委派事件

   1: private void Form1_Load(object sender, EventArgs e)
   2: {
   3:     button1.Click += delegate(System.Object o, System.EventArgs ea)
   4:     {
   5:         MessageBox.Show("訊息1:Click");
   6:     };
   7:     button1.MouseWheel += delegate(System.Object o, System.Windows.Forms.MouseEventArgs ms)
   8:     {
   9:         string str = ms.Delta > 0 ? "滾輪>0" : "滾輪<0";
  10:         MessageBox.Show("訊息2:MouseWheel" + str);
  11:     };
  12:  
  13: }

在撰寫Click事件前,  先了解匿名函式需委派傳入哪些參數???          

step1.

反白Click並按右鍵, 接著點選移至定義

image

step2.

繼續點選EventHandler按右鍵, 接著點選移至定義

image

step3.

可以追蹤到EventHandler的定義

   1: namespace System
   2: {
   3:     // 摘要:
   4:     //     代表處理不含事件資料之事件的方法。
   5:     //
   6:     // 參數:
   7:     //   sender:
   8:     //     事件的來源。
   9:     //
  10:     //   e:
  11:     //     未包含任何事件資料的 System.EventArgs。
  12:     [Serializable]
  13:     [ComVisible(true)]
  14:     public delegate void EventHandler(object sender, EventArgs e);
  15: }

其中EventHandler引數的部分主要有兩個object(哪個物件觸發)和EventArgs(事件種類)

step4.

因此, 上面button1的Click Event可以定義如下:

   1: button1.Click += delegate(System.Object o, System.EventArgs ea)
   2: {
   3:     ...
   4: }
===================================================================================================

step5.

依樣畫葫蘆, 我們也可以追蹤MouseWheel事件該如何定義delegate function

反白MouseWheel並按右鍵, 接著點選移至定義

image

step6.

同上一個步驟, 反白MouseEventHandler, 並按右鍵並選擇<移至定義>,

   1: //
   2:   // 摘要:
   3:   //     發生於控制項擁有焦點,且移動滑鼠滾輪時。
   4:   [EditorBrowsable(EditorBrowsableState.Advanced)]
   5:   [SRDescription("ControlOnMouseWheelDescr")]
   6:   [Browsable(false)]
   7:   [SRCategory("CatMouse")]
   8:   public event MouseEventHandler MouseWheel;

step7.

可以追蹤到MouseEventHandler的delegate function需要兩的引數objectMouseEventArgs

   1: namespace System.Windows.Forms
   2: {
   3:     // 摘要:
   4:     //     表示處理表單、控制項或其他元件之 MouseDown、MouseUp 或 MouseMove 的方法。
   5:     //
   6:     // 參數:
   7:     //   sender:
   8:     //     事件的來源。
   9:     //
  10:     //   e:
  11:     //     包含事件資料的 System.Windows.Forms.MouseEventArgs。
  12:     public delegate void MouseEventHandler(object sender, MouseEventArgs e);
  13: }

step8.

因此, 上面button1的MouseWheel Event可以定義如下

   1: button1.MouseWheel += delegate(System.Object o, System.Windows.Forms.MouseEventArgs ms)
   2: {
   3:    ...
   4: }

---------------------------------------------------------------------------------------------------------------------------------------------------------

[重點2]

(1) 宣告語法: delegate output argument 委派名稱(input arguments)

output argument: 可以為void, 或 int, double,…等

input argument: 例如可以為一個整數輸入 (int x),  兩個雙精準度輸入 (double x, double y)…等

(2) 利用匿名方法初始化   委派物件,  PS.匿名方法的輸入輸出個數必須和宣告時相同 

下面定義兩個委派函式(delegate function), 分別為 multiply和timestwo, 前者兩個輸入引數, 後者一個輸入引數

第4,5行分別匿名方法初始化timestwo和multiply物件(t, m)

   1: delegate int multiply(int x, int y);
   2: delegate int timestwo(int x);                    // [1] 新增一個叫做timestwo的delegate,其輸入個數 = 1, 輸出個數=1 
   3:  
   4: timestwo t = delegate(int x) { return 2 * x; };  // 定義一個timestwo變數t, 利用匿名方法初始化之 
   5: multiply m = delegate(int x, int y) { return x * y; };
   6: private void button2_Click(object sender, EventArgs e)
   7: {
   8:     MessageBox.Show(t(5).ToString());
   9:     MessageBox.Show( m(5, 6).ToString());
  10: }

[重點3]

delegate型別物件s1和s2, 分別用不同的匿名函式實作(初始化)之,

利用產生隨機亂數, 若>0.5  回傳字串s1  字串"Hello world!" 否則回傳s2 字串"It's me, Ryan!"

   1: delegate string sayHi();                         // [2] 新增一個叫做sayHi的delegate,其輸入個數 = 0, 輸出個數=1
   2:   sayHi s1 = delegate() { return "Hello world!"; }; // 定義一個SayHi變數s1, 利用匿名方法初始化之 
   3:   sayHi s2 = delegate() { return "It's me, Ryan!"; };
   4:   private void button3_Click(object sender, EventArgs e)
   5:   {
   6:       Random c = new Random();
   7:       double x = c.NextDouble();
   8:       string str = x > 0.5 ? s1() : s2();
   9:       MessageBox.Show(x.ToString() + str);
  10:   }

-------------------------------------------------------------------------------------------------------------------------------------------------------

[重點4]另一種常見的應用: 在定義執行緒的副程式上

以下為ThreadStart的  delegate function定義: 無輸入引數狀況

   1: public delegate void ThreadStart();
   1: private void button4_Click(object sender, EventArgs e)
   2: {
   3:     
   4:         Thread th = new Thread(
   5:         delegate()               // 匿名方法: 輸入/輸出個數=0
   6:         {
   7:             while (true)
   8:             {
   9:                 System.Console.Write("Hello, ");
  10:                 System.Console.WriteLine("World!");
  11:             }
  12:         }
  13:     
  14:         );
  15:         th.Start();
  16: }

一個輸入引述狀況

   1: public delegate void ParameterizedThreadStart(object obj);

測試如下

   1: private void button7_Click(object sender, EventArgs e)
   2:         {
   3:             Thread th = new Thread(DoJob);
   4:             int x = 5;
   5:             
   6:             th.Start(x);
   7:         }
   8:         public static void DoJob(object data)
   9:         {
  10:             
  11:             while(true)
  12:             {
  13:                Console.WriteLine("Static Thread procedure.Data = '{0}''",data);
  14:             }
  15:         }

將Thread結果顯示在人機介面上, 必須利用Invoke這個指令

   1: Thread th = new Thread(delegate()           // 匿名函式
   2:   {
   3:       int cnt = 0;
   4:       while (true)
   5:       {
   6:           cnt++;
   7:           this.Invoke(                   // 將程式碼交給主線程執行
   8:           (MethodInvoker)delegate()      //使用匿名方法
   9:           {
  10:               label1.Text = cnt.ToString();
  11:           }
  12:           );  //Invoke
  13:       }
  14:       
  15:   });
  16:   th.Start();

-------------------------------------------------------------------------------------------------------------------------------------------------------

[重點5]

delegate 可以與具名方法(Named Methods)或是匿名方法(Anonymous Methods)產生關聯

以下範例利用addSomething具名方法來實體化匿名方法addNumber物件a

 

   1: delegate int addNumber(int x);
   2:         // Define a named method:
   3:         static int addSomething(int x) { return x + 2; }
   4:         private void button6_Click(object sender, EventArgs e)
   5:         {
   6:             // 具名方法
   7:             addNumber a = addSomething;
   8:             
   9:             MessageBox.Show( a(5).ToString() );
  10:  
  11:             // 匿名方法
  12:             a = delegate(int x) { return 2 * x; };
  13:             MessageBox.Show(a(5).ToString());
  14:         }

-------------------------------------------------------------------------------------------------------------------------------------------------------

(1) 利用匿名方法(Anonymous Methods)初始化delegate物件

(2) 利用具名方法(Named Methods)初始化delegate物件

   1: delegate void Printer(string s);
   2:        static void DoWork(string k)
   3:        {
   4:            System.Console.WriteLine(k);
   5:        }
   6:        private void button5_Click(object sender, EventArgs e)
   7:        {
   8:            Printer p = delegate(string str)  // (1) 利用匿名方法初始化delegate
   9:            {
  10:                System.Console.WriteLine(str);
  11:            };
  12:            // Results from the anonymous delegate call.
  13:            p("(1)匿名方法(Anonymous Method)傳給delegate");
  14:            //------------------------------------------------------------------
  15:            p = new Printer(DoWork);   // (2)利用命名方法初始化delegate
  16:            // Results from the old style delegate call.
  17:            p("(2)命名方法(Named Method)傳給delegate");
  18:  
  19:        }

                                                                                                                                                                                                                   

附註:

在 C# 2.0 以前的版本中,宣告委派 (Delegate) 的唯一方式是使用具名方法(Named Methods)

C# 2.0 引進了匿名方法 (Anonymous Method)

C# 3.0 (含) 以後版本,則以 Lambda 運算式取代匿名方法來做為撰寫內嵌 (Inline) 程式碼的慣用方式

 


 

 

相關資料

  1. Anonymous Methods (C# Programming Guide)

  2. Delegates with Named vs. Anonymous Methods (C# Programming Guide)

  3. Lambda Expressions (C# Programming Guide)

  4. 如何將執行緒運算結果顯示於人機介面上?

arrow
arrow
    全站熱搜

    me1237guy 發表在 痞客邦 留言(0) 人氣()