c#深入剖析(1)——事件
準備寫乙個系列文章,深入**c#及.net中的某些特性。
第一篇 事件
事件相信每個人都不陌生,隨便乙個winform程式,就會使用大量的事件,比如:
c# code
class當然,還可以對**進行簡化,如型別的自動推斷,匿名方法,lambda表示式等。這個事件大概的工作流程為:當使用者單擊窗體時,作業系統向應用程式傳送一系列訊息,如左鍵按下和左鍵抬起,應用程式將通過getmessage等方法最終將訊息提交到視窗過程(wndproc),視窗過程通過處理訊息,當發現產生了連續的左鍵按下和左鍵抬起的訊息後,mainform : form
private
void
mainform_click(
object
sender, eventargs e)
}
就知道產生了單擊事件,於是去呼叫窗體的onclick方法,該方法會去檢測一下是否訂閱了click事件,如果訂閱了,就會去呼叫相應的事件處理程式,這個過程是通過委託實現的。
下面我從語法角度來分析一下事件:
事件是類、結構或介面中的乙個成員,它有兩種定義形式:
一、 c# code
eventmethodinvoker oneevent;
二、 c# code
event是乙個沒有引數和返回值的委託,它只是用來約束事件處理程式的的形式,你可以任意定義乙個,例如你可以使用action來代替。methodinvoker oneevent
remove
}其中methodinvoker
事件包括兩個訪問器,其中add訪問器會在訂閱事件時觸發,remove訪問器在取消事件訂閱時觸發。
對於第一種定義形式,系統會自動提供add及remove訪問器,同時會提供如下字段:
c# code
private該字段的型別為委託的型別,欄位名跟事件名相同(乙個類中擁有同名成員,c#編譯器是不允許的,但是系統可以)。methodinvoker oneevnet;
c# code
class
demo
}public
event
methodinvoker oneevent;
public
event
func
<
int,
string
>
twoevent;
}
private
void
button1_click(
object
sender, eventargs e)
;de.twoevent
+=arg
=>
arg.tostring();
de.invokeevent();
}
可以看出,這裡事件類似於方法和委託,可以傳遞引數並被呼叫。事實上,這只是編譯器的一種包裝,這裡其實使用的正是前面提到的同名的委託字段。而如果是在乙個類中訪問另乙個類中的事件,或者如下面將要提到的自己提供訪問器的情況,由於不存在同名的委託字段,事件就不能再這樣使用了,而只能出現在+=和-=運算子的左側。
至少有兩個理由使得我們需要自己提供訪問器:
1. 希望在訂閱或取消事件時執行一段**。
2. 前面提到,如果不提供訪問器,每定義乙個事件,系統就會生成乙個同名的委託字段,如果事件特別多,這就是一項巨大的開銷,而如果定義了訪問器,則不再提供,此時我們可以用一種統一的方式來處理,從而節省資源,實際上,winform就是這樣處理的。
c# code
可以看到,只有pr.oncall和pro.oncalls訂閱成功了,並且pro.oncalls不能被取消。class
demo
}eventhandlerlist ehl
=new
eventhandlerlist();
static
readonly
object
oneevent
=new
object
();
static
readonly
object
twoevent
=new
object
();
public
event
methodinvoker oneevent
remove
}public
event
func
<
int,
string
>
twoevent
remove
}public
void
oncall()
}class
pro
public
void
oncall()
public
static
void
oncalls()
}
private
void
button1_click(
object
sender, eventargs e)
再來簡單說說winform事件:
winform的根是元件(component),可視的元件稱為控制項(control)。
component上定義了乙個受保護的屬性events,用於管理事件列表。
control上定義了一系列靜態的私有字段,為事件列表提供索引鍵,欄位名基本上是:
event事件名
如eventclick,evententer等。
舉乙個應用:
如何獲取乙個事件訂閱的所有方法列表,以及如何在不知道事件處理程式方法名的情況下取消事件,或者更現實一點,如何取消匿名方法(在不宣告乙個委託引用的前提下,匿名方法顯然不可能通過-=運算子來取消)。
c# code
這段**可以顯示button2的click事件訂閱的所有方法,並且在執行該段**後,button2的click事件將失效。private
void
button1_click(
object
sender, eventargs e)
}
也許有人會有這樣的疑問:getinvocationlist獲得的委託陣列中,某個委託如果還是包括多個方法鏈怎麼辦?微軟為大家想得非常周到了——陣列中的每個委託都僅表示一種方法。
另外,如果我們需要取消所有事件,不用遍歷,直接呼叫eventhandlerlist.dispose方法即可。
關於winform事件,還有乙個有趣的現象:
當我們拖曳乙個控制項到窗體時,雙擊該控制項就會進入某個事件處理程式,例如雙擊button控制項,會進入click事件;雙擊textbox控制項,會進入textchanged事件。你是否思考過怎麼通過程式設計的方法知道會進入哪個事件呢?
其實這叫做預設事件(類似的,還有乙個預設屬性的概念),是乙個特性:defaulteventattribute
c# code
[defaultevent("click")]
class
control
click是應用於control類的預設事件,button則繼承了這個特性,而textboxbase這個類將這個特性修改為textchanged, textbox又從textboxbase繼承過來這個特性。
既然知道了原理,要去檢索,就很簡單了,直接反射就行了。另外,其實系統提供有專門的方法:
c# code
typedescriptor.getdefaultevent。
現在來看看treeview控制項的預設事件:
c# code
attribute attr=attribute.getcustomattribute(
typeof
(treeview),
typeof
(defaulteventattribute));
defaulteventattribute de
=attr
asdefaulteventattribute;
messagebox.show(de.name);
或者 messagebox.show(typedescriptor.getdefaultevent(typeof(treeview)).name);
結果正是afterselect。
深入剖析C 的多型
一 什麼是多型 物件導向程式設計中的另外乙個重要概念是多型性。在執行時,可以通過指向基類的指標,來呼叫實現 派生類中的方法。可以把一組物件放到乙個陣列中,然後呼叫它們的方法,在這種場合下,多型性作用就體現出來了,這些物件不必是相同型別的物件。當然,如果 它們都繼承自某個類,你可以把這些派生類,都放到...
深入剖析C 的多型
天雨 一 什麼是多型 物件導向程式設計中的另外乙個重要概念是多型性。在執行時,可以通過指向基類的指標,來呼叫實現派生類中的方法。可以把一組物件放到乙個陣列中,然後呼叫它們的方法,在這種場合下,多型性作用就體現出來了,這些物件不必是相同型別的物件。當然,如果它們都繼承自某個類,你可以把這些派生類,都放...
C 深入剖析 委託設計
c 深入剖析 委託設計 程式 結論一 圖 一 實現的功能都是由圖 二 提供的類來完成的 結論二 兩者的建構函式和析構函式不存在任何關係 結論三 採用指標的方式,這樣左邊對外介面可以不發生改變。如果要改變某個功能只需要改變指標所對應的類 模式二 資料共享的模式 a b c 都是class string...