.net的委託和事件的直接理解 (轉)
初學者在理解委託和事件時常常被msdn搞糊塗,為了讓初學的人應用.net的委託和事件模型,我在這裡主要是提出理解的關鍵,以下程式碼都可直接執行,先看下面的程式碼。
using System;
namespace delegeteTest
{
class delegeteClass
{
public delegate void fHandler(int a); //關鍵-此行可以看成類的宣告
public fHandler f0;
public void d(int a,int b )
{
int c=a+b;
f0(c);
}
}
class test
{
public void output(int mun)
{
System.Console .WriteLine ("{0}",mun);
}
[STAThread]
static void Main(string[] args)
{
test t=new test ();
delegeteClass dc=new delegeteClass ();
dc.f0 =new delegeteTest.delegeteClass.fHandler (t.output);//例項的初始化
dc.d(2,3);
}
}
}
解釋一下"關鍵": 實際上 public delegate void fHandler(int a);可以看成如下:
class fHandler
{.....}
類內部由自動完成,是一個sealed類透過反可以看到,是一個類的宣告,它檢查加入自己的的資訊,如,返回值和引數型別
現在熟悉vc++的人可能感覺到public delegate void fHandler(int a);這句就象一個宏
現在好了既然是個類的定義,那麼也可以直接拿到名稱空間下了
using System;
namespace delegeteTest
{
public delegate void fHandler(int a);//fHandler現在上升到了類的層次
class delegeteClass
{
public fHandler f0;//宣告瞭委託fHandler的例項f0;
public fHandler f1;//也可以再宣告一個fHandler類的例項f1;
public void d(int a,int b )
{
int c=a+b;
f0(c);
}
}
class test
{
public void output(int mun)
{
System.Console .WriteLine ("{0}",mun);
}
[STAThread]
static void Main(string[] args)
{
test t=new test ();
delegeteClass dc=new delegeteClass ();
dc.f0 =new delegeteTest.fHandler (t.output);//此行做相應的修改
dc.d(2,3);
}
}
}
有以上可知public delegate void fHandler(int a)這行程式碼只能放在能夠宣告類的地方,自然fHandler.後面的函式都是靜態方法了,如fHandler.Equals (...);
那麼fHandler到底宣告瞭什麼? 實際上是宣告瞭函式的型別,既函式的有關資訊(如返回值,引數型別)。說到委託還是要說一下委託型別的例項。在msdn中的很多地方,(委託)這個詞指的是委託型別的例項,它擁有了一個列表,列表的每一項包含了函式資訊和函式所在的的引用。
在宣告fHandler類的例項f0的時候,f0還不能用,是空的,所以f0需要初始化 dc.f0 =new delegeteTest.fHandler (t.output); 初始化的引數包含了兩個資訊 t--物件的引用,output--函式資訊,如果把初始化的這句註釋掉,你執行一下看有什麼資訊----“未將物件引用設定到物件的例項”。另外output函式的引數和返回值需要和fHandler的類宣告一致,這是由編譯器在編譯時檢查的。
經過初始化之後 現在例項中有了一項資料(實際上大多數只有一項,這樣比較高,也就是single cast的,此時例項是Delegate型別的(注意是大寫的D))。
現在說一下委託的多播(multi cast),實際上委託的多播就是把列表裡的每一項函式一次),但是多播的效率不是很高的所以委託的大部分例項都是單播(single cast),另外可能委託的例項會根據列表內函式的個數來執行不同的機制(這裡我們就沒必要研究它了)。看下面的程式碼:
namespace delegeteTest
{
public delegate void fHandler(int a);
class delegeteClass
{
public fHandler f0;
public fHandler f1;
public void d(int a,int b )
{
int c=a+b;
f1(c); //合併指標列表的多播委託
}
}
class test
{
public void output(int mun)
{
System.Console .WriteLine (" 函式1顯示{0}",mun);
}
public void output1(int mun)
{
System.Console .WriteLine (" 函式2顯示{0}",mun);
}
[STAThread]
static void Main(string[] args)
{
test t=new test ();
delegeteClass dc=new delegeteClass ();
dc.f0 =new delegeteTest.fHandler (t.output);
dc.f1 =new fHandler (t.output1 );
System.Console .WriteLine ("第一次觸發");
dc.d (2,3);//第一次觸發
dc.f1 =(fHandler)Delegate.Combine (dc.f0 ,dc.f1 );//合併生成新的]函式列表
dc.f1 =(fHandler)MulticastDelegate.Combine (dc.f1 ,dc.f0 );//同上
System.Console .WriteLine ("第二次觸發");
dc.d(2,3);//第二次觸發
}
}
}
實際上dc.f1 =(fHandler)MulticastDelegate.Combine (dc.f1 ,dc.f0 );和dc.f1 =(fHandler)Delegate.Combine (dc.f1 ,dc.f0 );效果是一樣的;由上面的例子可知我們完全可以由delegate 來構造我們自己的事件。為了方便大家進行程式設計,為我們提供了event。
using System;
namespace delegeteTest
{
public delegate void fHandler(int a);
class delegeteClass
{
public fHandler f0;
public fHandler f1;
public event fHandler f3; //關鍵--實際上此行也可以看成一個宏
public void d(int a,int b )
{
int c=a+b;
f3(c); // 改由event進行
}
}
class test
{
public void output(int mun)
{
System.Console .WriteLine (" 第1顯示{0}",mun);
}
public void output1(int mun)
{
System.Console .WriteLine (" 第2顯示{0}",mun);
}
[STAThread]
static void Main(string[] args)
{
test t=new test ();
delegeteClass dc=new delegeteClass ();
dc.f0 =new delegeteTest.fHandler (t.output);
dc.f1 =new fHandler (t.output1 );
dc.f3 +=new fHandler(t.output); //f3是event
System.Console .WriteLine ("第一次觸發");
dc.d (2,3);//第一次觸發
System.Console .WriteLine ("第二次觸發");
dc.f3 +=(fHandler)Delegate.Combine (dc.f0 ,dc.f1 );//新增列表到f3
dc.d(2,3);//第二次觸發
}
}
}
透過ildasm反彙編可以看到public event fHandler f3宏宣告瞭兩個成員
.field private class delegeteTest.fHandler f3和對f3的一個包裝:
.event delegeteTest.fHandler f3
{
.addon instance void delegeteTest.delegeteClass::add_f3(class delegeteTest.fHandler)
.removeon instance void delegeteTest.delegeteClass::remove_f3(class delegeteTest.fHandler)
},
所以上面紅色的程式碼可以替換成如下:
private fHandler _f3;//由於不能與屬性名相同,所以用_f3,是私有
public event fHandler f3
{
add
{
this._f3 += value;
}
remove
{
this._f3 -= value;
}
}
event 關鍵字方便了大家的習慣,同時它(由event定義的事件)在類的外部使用時隱藏了它的成員函式(這一點非常重要,幾乎就是使用event關鍵字的原因),並且只能用“+=”和“-=”來操作,除此之外和直接宣告public fHandler f3沒有區別。它可以和上面的f0,f1一樣允許有各種引數和返回值(EventHandler是一個特定的委託,沒有返回值,引數是和EventArgs類(或繼承)的)。是在委託基礎上的。實際上我們都能用delegate 來構造我們想要的事件,這就是delegate 在.net裡的地位很高的原因。
下面我就說說一般的事件模型
我先談一下控制元件裡的"On事件名"這個函式 如:OnTextChange(EventArgs e),類似的有很多,實際上這是一種程式設計方面的習慣,他代表的是引發這個TextChanged事件(當然和上面一樣,包含一個委託onTextChanged和一個event包裝),具體的說就是在Text變數已經被賦值後的一個函式OnTextChanged(),OnTextChanged()裡面包含了類似onTextChanged(e)這樣的引發事件的程式碼。如果你重寫了OnTextChanged(),而沒有在(重寫的函式)裡新增base.OnTextChanged(e);那麼你在外部新增的TextChanged事件的處理,永遠也不會觸發到,也就是TextChanged事件失效了。
以上只是幫助大家理解,因為這樣才能事半功倍,尤其上面的關鍵,可以省了大家不少力氣。希望專家批評指正
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-963788/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- .NET委託,事件和Lambda表示式事件
- ASP.NET談委託和事件ASP.NET事件
- js 事件的冒泡和委託JS事件
- 事件模型和事件委託事件模型
- C# 中的委託和事件C#事件
- JS事件流和事件委託JS事件
- 委託、Lambda表示式、事件系列01,委託是什麼,委託的基本用法,委託的Method和Target屬性事件
- c# 委託和事件C#事件
- 事件委託事件
- C#中的委託和事件(續)C#事件
- JavaScript 中的閉包和事件委託JavaScript事件
- 委託、事件--委託例項篇事件
- C# 委託,事件和Lambda表示式 (轉)C#事件
- 委託與事件-委託詳解(一)事件
- C# 自定義事件和委託(精彩轉載)C#事件
- jQuery 事件委託jQuery事件
- ASP.NET中定製自己的委託和事件引數類ASP.NET事件
- 事件的捕獲、冒泡、委託事件
- javascript中的事件委託(代理)JavaScript事件
- jquery-中的事件委託jQuery事件
- Zepto事件委託的小坑事件
- 觀察者模式與.Net Framework中的委託與事件模式Framework事件
- C#:委託和自定義事件C#事件
- Asp.Net中的Action和Func委託ASP.NET
- 事件委託---動態建立的元素新增事件事件
- dotnet 委託的實現解析(2)開放委託和封閉委託 (Open Delegates vs. Closed Delegates)
- C#.Net築基-解密委託與事件C#解密事件
- 對js事件委託的瞭解JS事件
- JavaScript事件委託的技術原理JavaScript事件
- C# 事件委託C#事件
- C#事件委託事件
- 重中之重:委託與事件事件
- C# 委託事件C#事件
- wpf移除事件委託事件
- zt 對C#下函式,委託,事件的一點理解!C#函式事件
- 委託、Lambda表示式、事件系列04,委託鏈是怎樣形成的, 多播委託, 呼叫委託鏈方法,委託鏈異常處理事件
- Js 事件原理與事件委託JS事件
- .NET委託解析