C#程式設計之委託與事件(一)

iDotNetSpace發表於2009-05-15

    本文試圖在.net Framework環境下,使用C#語言來描述委託、事件的概貌。希望本文能有助於大家理解委託、事件的概念,理解委託、事件的用途,理解它的C#實現方法,理解委託與事件為我們帶來的好處。C#是一種新的語言,希望大家能通過本文清楚地看到這些,從而可以對委託、事件等技術進行更深入的理解和探索。

一. 委託

委託的本質
  --在C#中,委託是一個特殊的類;
  --在某種程度上,相當於C++的函式指標;
  --在某種程度上,相當於介面(Interface);

委託的定義
  --關鍵字:delegate
  --public delegate void MyDelegate(string message);
  注:在這裡我們先了解一個概念,什麼是函式簽名?(在這裡我不做過多解釋,大家知道這個概念就行)。

使用委託
  我們先來看看一個小的委託示例:
  平時,如果說我們要設計一個做簡單加減運算的方法,通常是怎麼做的呢?看看下面程式碼:  1class Program
 2    {
 3        /**////


 4        /// 加法運算
 5        ///

 6        /// x
 7        /// y
 8        ///
 9        private static int Add(int x, int y)
10        {
11            int result = x + y;
12            Console.WriteLine("x + y = {0}",result);
13            return result;
14        }
15
16        /**////
17        /// 減法運算
18        ///

19        /// x
20        /// y
21        ///
22        private static int Sub(int x, int y)
23        {
24            int result = x - y;
25            Console.WriteLine("x - y = {0}", result);
26            return result;
27        }
28
29        static void Main(string[] args)
30        {
31            Add(8, 8);
32            Sub(8, 1);
33            Console.Read();
34        }
35    }  
   上面的程式碼只要是學過程式的人都能看懂,也寫得出,不過我們怎麼通過委託來處理+,-運算呢?請看下面定義:
 1namespace DelegateSample1
 2{
 3    //定義一委託
 4    public delegate int OperationDelegate(int x,int y);
 5    public class Operator
 6    {
 7        private int _x, _y;
 8        public Operator(int x, int y)
 9        {
10            this._x = x;
11            this._y = y;
12        }
13
14        public void Operate(OperationDelegate del)
15        {
16            del(_x, _y);
17        }
18    }
19}
  上面定義一個返回int型別需要兩個int引數的委託。Operator裡提供了一個操作方法帶有一個委託引數。那通過委託怎麼來處理這個簡單的運算呢?好,現在我們來修改我們之前定義的主方法,如下:
 1namespace DelegateSample1
 2{
 3    class Program
 4    {
 5        /**////
 6        /// 加法運算
 7        ///

 8        /// x
 9        /// y
10        ///
11        private static int Add(int x, int y)
12        {
13            int result = x + y;
14            Console.WriteLine("x + y = {0}",result);
15            return result;
16        }
17
18        /**////
19        /// 減法運算
20        ///

21        /// x
22        /// y
23        ///
24        private static int Sub(int x, int y)
25        {
26            int result = x - y;
27            Console.WriteLine("x - y = {0}", result);
28            return result;
29        }
30
31        static void Main(string[] args)
32        {
33            //宣告一個委託物件
34            OperationDelegate del = null;
35            del += new OperationDelegate(Add);
36            del += new OperationDelegate(Sub);
37
38            Operator p = new Operator(5, 3);
39            op.Operate(del);
40            Console.ReadLine();
41        }
42    }
43}
44   從上面的例子看,委託OperationDelegate代表了一組方法,他們的方法簽名是:
   --返回值:int; 引數:int ,int ;
   只要符合該簽名的方法,都可以賦給此委託:從上面不難看出,我要要建立一委託,則如下定義:
1OperationDelegate del += new OperationDelegate(方法名);   從上面可以看到(+=)這個運算子,那是不是也有(-=)這個運算子呢?這就涉及到另外一個概念了--委託鏈。
   --委託鏈:實際上委託例項就是一個委託鏈,+=代表增加委託例項到委託鏈中,相反-=則代表去掉該委託例項。
1OperationDelegate del = null;
2del += new OperationDelegate(Add); //增加委託例項到委託鏈
3del -= new OperationDelegate(Add); //去掉委託例項到
委託的意義之一
  --委託可以使得程式的複用程度提高;
  --委託在一定程度上想當於介面;
  例如:前面例子中的方法Operate(),由於接受的是一個委託型別;那麼,我們可以對委託型別賦予不同的方法,來改變Operate()的性質。

  我們在來看看另外一個示例:
  --我們想輸出一串數字,從0-100;
  --對於輸出的要求有三種;
   -1、輸出到控制檯
   -2、輸出到窗體中的ListBox中;
   -3、輸出到文字檔案中;
  解決方案:
  --使用委託和介面, 程式碼如下:
 1namespace DelegateSample2
 2{
 3    //定義一委託
 4    public delegate void ShowNumberDel(object[] items);
 5    public class ProcessNumber
 6    {
 7        private object[] items;
 8        public ProcessNumber(int max)
 9        {
10            items = new object[max];
11            for (int i = 0; i < max; ++i)
12            {
13                items[i] = i;
14            }
15        }
16
17        public void ProcessItems(ShowNumberDel show)
18        {
19            show(items);
20        }
21    }
22}
23在這裡我們先把介面上的控制元件佈局好並做好呼叫委託的準備工作,效果及程式碼如下:
                   
程式碼如下:
 1private ProcessNumber pn = null;
 2ShowNumberDel del = null;
 3
 4private void Form1_Load(object sender, EventArgs e)
 5{
 6     pn = new ProcessNumber(100);
 7}
 8
 9//到控制檯
10private void ShowInConsole(object[] items)
11{
12    foreach (object item in items)
13    {
14        Console.WriteLine(item);
15    }
16}
17
18//到ListBox
19private void ShowInListBox(object[] items)
20{
21    listBox1.Items.Clear();
22    foreach (object item in items)
23    {
24        listBox1.Items.Add(item);
25    }
26}
27
28//到文字檔案
29private void ShowInFile(object[] items)
30{
31   using (StreamWriter sw = new StreamWriter("Test.txt", true))
32   {
33       foreach (object item in items)
34       {
35           sw.WriteLine(item);
36       }
37   }
38}使用委託:
 1private void button1_Click(object sender, EventArgs e)
 2{
 3    pn.ProcessItems(new ShowNumberDel(ShowInConsole));
 4}
 5
 6private void button2_Click(object sender, EventArgs e)
 7{
 8    pn.ProcessItems(new ShowNumberDel(ShowInListBox));
 9}
10
11private void button3_Click(object sender, EventArgs e)
12{
13    pn.ProcessItems(new ShowNumberDel(ShowInFile));
14}
15
16private void button4_Click(object sender, EventArgs e)
17{
18    del += new ShowNumberDel(this.ShowInListBox);
19    del += new ShowNumberDel(this.ShowInFile);
20
21    pn.ProcessItems(del);
22}完整的測試程式碼如下:
使用委託的完整測試程式碼
 1using System;
 2using System.Collections.Generic;
 3using System.ComponentModel;
 4using System.Data;
 5using System.Drawing;
 6using System.Text;
 7using System.Windows.Forms;
 8using System.IO;
 9
10namespace DelegateSample2
11{
12    public partial class Form1 : Form
13    {
14        public Form1()
15        {
16            InitializeComponent();
17        }
18
19        private ProcessNumber pn = null;
20        ShowNumberDel del = null;
21
22        private void Form1_Load(object sender, EventArgs e)
23        {
24            pn = new ProcessNumber(100);
25        }
26
27        private void ShowInConsole(object[] items)
28        {
29            foreach (object item in items)
30            {
31                Console.WriteLine(item);
32            }           
33        }
34        private void ShowInListBox(object[] items)
35        {
36            listBox1.Items.Clear();
37            foreach (object item in items)
38            {
39                listBox1.Items.Add(item);
40            }
41        }
42        private void ShowInFile(object[] items)
43        {
44            using (StreamWriter sw = new StreamWriter("Test.txt", true))
45            {
46                foreach (object item in items)
47                {
48                    sw.WriteLine(item);
49                }
50            }
51        }
52
53        private void button1_Click(object sender, EventArgs e)
54        {
55            pn.ProcessItems(new ShowNumberDel(ShowInConsole));            
56        }
57
58        private void button2_Click(object sender, EventArgs e)
59        {
60            pn.ProcessItems(new ShowNumberDel(ShowInListBox));
61        }
62
63        private void button3_Click(object sender, EventArgs e)
64        {
65            pn.ProcessItems(new ShowNumberDel(ShowInFile));
66        }
67
68        private void button4_Click(object sender, EventArgs e)
69        {
70            del += new ShowNumberDel(this.ShowInListBox);
71            del += new ShowNumberDel(this.ShowInFile);
72            pn.ProcessItems(del);
73        }  
74    }
75}
委託的意義之二
   --在C#中使用執行緒需要用到委託
    - Thread thread = new Thread(new ThreadStart(target));

−     -這裡的ThreadStart就是一個委託,他的定義是:
     -target既為符號ThreadStart委託的方法名;
 
   --函式回撥
    - 當我們定義了一個委託;
       public delegate void MyDelegate(int source);
    -對於非同步呼叫來說,就有BeginInvoke()和EndInvoke()方法; 
    -del.BeginInvoke(source, new System.AsyncCallback(CallBack), "test");

    -private void CallBack(IAsyncResult asyncResult)
      {
            int result = del.EndInvoke(asyncResult);
            //......
      }
  這裡需要理解的就是什麼叫函式回撥?這個話題留給大家討論,在此不作詳細解說。關於委託本文只是入門級的文章,要想更詳細深入的學習委託請檢視具體的書籍或資料,本文就簡單介紹到這裡。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-598257/,如需轉載,請註明出處,否則將追究法律責任。

相關文章