事件(event)與委託(delegate)

  事件(event)與委託(delegate)
1.談談函數指針
   一個函數在編譯時被分配給一個入口地址。這個入口地址就稱爲“函數的指針”。用一個指針變量指向函數,然後通過該指針變量調用此函數,這個指針變量就稱爲“指向函數的指針”。
void Main()
{
  
int Max(int,int);
  
//聲明一個函數指針
  int (*p)(int,int);
  
int a,b,c;
  
//
  
//把Max函數的入口地址賦給指針變量p
  p=Max;
  
//函數指針的形式調用Max函數
  c=(*p)(a,b);
}
   下面我們再來看看回調函數:
   如果給p賦不同的值(不同的函數地址),那麼調用者就能調用不同的函數;賦值可以發生在運行時,從而實現動態綁定。這裏的調用者即我們要談的回調函數。
int Main()
{
  
int Max(int,int);
  
int Min(int,int);
  
//
  int (*p)(int,int);
  
//p=Min;
  p=Max;
  
//傳遞函數地址給調用者
  Caller(p);
}


//回調函數
void Caller(int (*ptr)(int,int))
{
  
//調用ptr指向的函數
  ptr();
}
      
2.什麼是委託
   
以下內容來自:http://www.cnblogs.com/WuCountry/archive/2006/11/29/576030.html
   先來看下面的代碼:
using System;
namespace ConsoleApplication1
{
    
class Class1
    
{
        [STAThread]
        
static void Main(string[] args)
        
{
            
bool m_isRight = false;
            
object m_obj = m_isRight?MyWrite("true"):MyWrite("false");
            Console.Write(m_obj);
        }

        
static private int MyWrite(object i_string)
        
{
            Console.Write(i_string);
            
return i_string.ToString().Length;
        }

    }

}

   如果認爲Console.Write(m_obj);等於是Console.Write(MyWrite("false"));這顯然不對!
   如果真要給m_obj對象賦予函數MyWrite(),會怎麼樣呢?
   把函數當成變量賦給對象,我們首先得解決三個問題:
   1、如果可以對一個對象賦函數值,如何區別不同的函數;
   2、如何給這個對象賦函數值;
   3、如何用這個對象調用原來的函數;
   對於第一個問題,首先我們應認識到c#中是可以對一個對象賦函數值的;解決這個問題的辦法是先對該對象聲明,聲明它可以被什麼樣的函數來賦值,而這個對象聲明在C#裏的學名就是委託。這和上面講到的函數指針十分類似(其實委託的內部機制比函數指針複雜的多)。
   現在我們可以聲明如下的委託來解決問題一:
delegate int MyDelegate(object i_object);
//
MyDelegate m_delegate = new MyDelegate(MyWrite);
//MyWrite函數如下,它是滿足委託的申明的。
                   static private int MyWrite(object i_string)
                   
{
                            Console.Write(i_string);
                            
return i_string.ToString().Length;
                   }
   委託聲明:MyDelegate m_delegate = new MyDelegate(MyDelegate申明一致的函數名);
   這樣就完美的解決了第一個問題。
   OK,第二個問題。如何給這個對象m_delegate賦函數值?其實上面在實例化委託對象時,已經對其賦值MyWrite,因此它已經具有了MyWrite函數的功能。只有這種方法對其進行賦值麼?不,另一種賦值形式就是事件。
   我們再來看第三個問題,這個問題看下面的代碼就清楚了:
using System;
namespace ConsoleApplication1
{
    
class Class1
    
{
        
//先申明一個委託對象。
        delegate int MyDelegate(object i_object);
        [STAThread]
        
static void Main(string[] args)
        
{
            MyDelegate m_delegate 
= new MyDelegate(MyWrite);
            m_delegate(
"This is a delegate object to call the raw function.");
        }

        
//該函數是滿足上面委託對象的申明的。
        static private int MyWrite(object i_string)
        
{
            Console.Write(i_string);
            
return i_string.ToString().Length;
        }
        
    }

}


3.事件與事件委託 
   事件是對象發送的消息,以發信號通知操作的發生。操作可能是由用戶交互(例如鼠標單擊)引起的,也可能是由某些其他的程序邏輯觸發的。引發事件的對象稱爲事件發送方。捕獲事件並對其作出響應的對象叫做事件接收方。(MSDN)
   事件是基於委託的,而由上面的定義可以知道我們將要遇到的問題是:
   1、如何動態的(運行時)對“特殊委託”賦函數值,怎樣實現?
   2、運行時,如何知道“特殊委託”已經被賦過值及如何賦值?
   3、能否在“特殊委託”上添加多個函數值?如果可以,如何刪除?

   相信大家已經知道這個“特殊委託”就是我們要談的事件。來看一下它的聲明:
   public event MyDelegate m_myevent;//聲明事件(第一個問題)
   public MyDelegate m_mydelegate;//聲明委託
   是不是很像?我們來看看它們的區別:
   1、事件不能直接把函數當值一樣賦給它的委託;而委託可以直接賦函數;
  2、事件只能把一個實例的委託當值賦給它;也就是說事件是用來管理委託的,進而管理函數。因爲一個實例化的委託肯定有一個函數與之對應。
  3、在一個事件上可以動態添加或刪除委託;而委託上不能動態添加或刪除函數。
  OK,我們來看看第二個問題。如何賦值?它的賦值有點怪:
  m_myevent += m_mydelegate;
  這裏也正好說明了事件是動態管理委託的。
  那麼又如何刪除?m_myevent -= m_mydelegate;沒有委託的情況下可以刪除麼?答案是肯定的。
  最後看一個完整的例子(從中可以知道如何判斷事件是否已賦過值):
 

using System;
namespace ConsoleApplication1
{
    
class Class1
    
{
        
//先聲明一個委託對象。
        delegate int MyDelegate(object i_object);
        
//聲明一個事件對象
        static event MyDelegate m_myevent;
        [STAThread]
        
static void Main(string[] args)
        
{
            
//實例化委託
            MyDelegate m_delegate = new MyDelegate(MyWrite);
            m_delegate(
"This is a delegate object to call the raw function.");
            
//實例化的委託賦值給事件
            m_myevent += m_delegate;
            m_myevent 
+= new MyDelegate(MyWrite);
            m_myevent 
+=new MyDelegate(Class1_m_myevent);
            
//判斷事件是否已賦過值
            if(m_myevent!=null)
            
{
                m_myevent(
"This is a event to call the funcaion on the delegate.");
            }
            
        }

        
//該函數是滿足上面委託對象的申明的。
        static private int MyWrite(object i_string)
        
{
            Console.WriteLine(i_string);
            
return i_string.ToString().Length;
        }


        
private static int Class1_m_myevent(object i_object)
        
{
            Console.WriteLine(i_object);
            
return 0;
        }

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章