天天看點

【原創】ASP.NET開發 筆試題目詳解系列(三)

    出處:http://blog.csdn.net/caoxicao

    作者:草惜草

    轉載請注明出處

問題四 C# 中的委托是什麼?事件是不是一種委托? : 委托

委托是C#中的一種引用類型,類似于C/C++中的函數指針。與函數指針不同的是,委托是面向對象、類型安全的,而且委托可以引用靜态方法和執行個體方法,而函數指針隻能引用靜态函數。委托主要用于 .NET Framework 中的事件處理程式和回調函數。

 一個委托可以看作一個特殊的類,因而它的定義可以像正常類一樣放在同樣的位置。與其他類一樣,委托必須先定義以後,再執行個體化。

委托派生于基類System.Delegate,不過委托的定義和正常類的定義方法不太一樣。委托的定義通過關鍵字delegate來

定義

public

delegate

int myDelegate(int x,int y);

上面的代碼定義了一個新委托,它可以封裝任何傳回為int,帶有兩個int類型參數的方法。任何一個方法無論是執行個體方法還是靜态方法,隻要他們的簽名(參數類型在一個方法中的順序)和定義的委托是一樣的,都可以把他們封裝到委托中去。

産生委托執行個體和産生類執行個體(對象)差不多,假如我們有如下的方法:

public int sub(int x,int y){

       return(x+y);

}

我們就可以使用如下的代碼得到一個

委托執行個體

myDelegate

calculatin

=new myDelegate(sub);

//

呵呵,用方法名!!!

 接下來我們就可以直接使用calculation調用sub方法了:

calculation

(10,3);

當然也可以建立

委托數組

,如下就建立了一個委托數組Calculation[]

 接下來我們就可以直接使用calculation調用sub方法了:

calculation

(10,3);

當然也可以建立

委托數組

,如下就建立了一個委托數組Calculation[]

 接下來我們就可以直接使用calculation調用sub方法了:

calculation

(10,3);

當然也可以建立

委托數組

,如下就建立了一個委托數組Calculation[]

       private delegate int Calculation(int a, int b);

       private static Calculation[] myCalculation=new Calculation[2];

此時,可以用委托數組中的成員來封裝待委托方法,實作建立委托執行個體.

如:

myCalculation[0]=new Calculation(MathClass.max); // 方法名

myCalculation[1]=new Calculation(MathClass.min); // 方法名

這樣,也就可以用建立的委托執行個體數組,來直接調用方法了.

事件

在C#中,委托的最基本的一個用處就是用于事件處理。是對象發送的消息,以發信号通知操作的發生,通俗一點講,事件就是程式中産生了一件需要處理的信号。

事件的定義用關鍵字event聲明,不過聲明事件之前必須存在一個多路廣播委托(一個委托同時委托多個方法):

public delegate void Calculate(int x,int y);//傳回值為void的委托自動成為多路廣播委托;

public event  Calculate OnCalculate;

可以看出,事件的聲明僅僅是比委托執行個體的聲明多了個關鍵字event,事實上

事件可以看作是一個為事件處理過程定制的多路廣播委托

。是以,定義了事件後,我們就可以通過向事件中

操作符 +=

添加方法實作事件的預定或者是通過

操作符 -=

取消一個事件,這些都與委托執行個體的處理是相同的。

下面再單獨談談

事件代理

的相關概念及其應用:

我們就一起來模仿一個Button類及Button值改變後引發事件并執行自定義的ButtonTextChangeEvent事件處理函數的過程,進而以事件資料得到該Button指派過多少次。

Using System;

namespace MyServerControlTest {

   public delegate void ButtonTextChangeEventHander ( object sender , EventArgs e ); //事件委托的聲明。

   public class Button {

   public event ButtonTextChangeEventHander TxtChange;//定義一個事件委托的引用,以備外部進行事件的綁定.

   private string _Text;;

   public string Text {

            get { return _Text;; }

       set {

                     _Text = value;;

                     System.EventArgs e = new EventArgs();; //這裡是事件的基類執行個體.

                     ChangeTxt(e);; //調用事件處理函數.

                }

   }

   private void ChangeTxt(EventArgs e)  { //事件處理函數.

   if( TxtChange != null )

   TxtChange(this,e);;//真正調用外部指派的處理函數.

   }

   }

}

為什麼要這樣定義委托聲明:

delegate ButtonTextChangeEventHander (Object sender , EventArgs e )

原因也很簡單,為了符合.net framework CLS的約定

Sender :引發事件的對象 ; e:事件所帶的資料,而之是以用EventArgs e 是因為這裡的事件是無資料的,如果自定義具有資料的事件的話,還是要從System.EventArgs基類中繼承。

需要指出的是:

if( TxtChange != null )

   TxtChange(this,e);;

如果不加 if( TxtChange != null )

那麼當TxtChange并沒有綁定事件處理函數時,它将會引發“未将對象引用到執行個體”的Exception。

   /** 〈summary〉

   /// 事件處理類

   /// 〈/summary〉

   public class DelegateDemo {

   //定義一個執行個體

   private Button button;

   public DelegateDemo(){

   InitializeComponent();

   //構造函數調用時,就開始操作button進行指派。

   SetValues();

}

   public void InitializeComponent(){

   button = new Button();;

   //對button對象的TxtChange事件引用,進行事件與處理函數的綁定。

   //前面已經說過了,EventHandler是一個類,是以要用new進行建立它的執行個體,其主要是把button_TxtChange事件處理函數的位址傳至這個委托執行個體。

   button.TxtChange

+=

new ButtonTextChangeEventHander(button_TxtChange);;

   }

   public void SetValues() {

   string[] values = {"AAA","BBB","CCC","DDD","EEE"};;

             for( int i = 0;; i 〈 5;; i++ ) {

            //進行指派,進而引發事件而直接調用button_TxtChange事件處理函數。

             button.Text = values[i];;

            }

   }

  private void button_TxtChange(object sender, System.EventArgs e) {

   Console.WriteLine( " Button執行個體新值。其值為:" + ((Button)sender).Text );

   }

}

   public class MyMain  {

            public static void Main() {

             DelegateDemo delegateDemo = new DelegateDemo();;

             Console.Read();;

        }

   }

}

感覺還是講的不是很清楚。再來看一個:

public class MyObject

{

   public delegate void ClickHandler(object sender, EventArgs e);

   public event ClickHandler Click;

   protected void OnClick()

   {

      if (Click != null)

         Click(this, null);

   }

}

ClickHandler 代理使用事件代理的标準模式來定義事件的簽名。其名稱的末尾是處理程式,它帶有兩個參數。第一個參數是發送對象的對象,第二個參數用于傳遞事件的伴随資訊。這種情況下沒有要傳遞的資訊,是以直接使用 EventArgs,但是如果有資料要傳遞,則使用從 EventArgs 派生的類(例如 MouseEventArgs)。

“Click”事件的聲明執行兩項操作:首先,它聲明一個名為“Click”的代理成員變量,該變量從類的内部進行使用。其次,它聲明一個名為“Click”的事件,該事件可按照正常通路規則從類的外部進行使用。

通常,将包括 OnClick() 等函數,以便使類型或派生類型能夠觸發事件。由于“Click”是代理,您将會注意到,用來觸發事件的代碼與代理的代碼相同。

與代理類似,我們使用 += 和 -= 來挂接到事件或解除事件挂接,但與代理不同的是,僅可對事件執行這些操作。這可確定不會發生先前所讨論的兩種錯誤。

使用事件是一種直截了當的方法。

class  Test

{

    static   void  ClickFunction( object  sender, EventArgs args)

   {

       //  process the event here.

   }

    public   static   void  Main()

   {

      MyObject myObject  =   new  MyObject();

      myObject.Click  +=   new  MyObject.ClickHandler(ClickFunction);      

   }

}

我們建立一個與代理簽名相比對的靜态函數或成員函數,然後用 += 向事件中添加代理的一個新執行個體