當前位置:編程學習大全網 - 編程語言 - 深入解析C#編程中的事件

深入解析C#編程中的事件

 壹個事件是壹個使對象或類可以提供公告的成員 用戶可以通過提供事件句柄來為事件添加可執行代碼 事件使用事件聲明來聲明 壹個事件聲明既可以是壹個事件域聲明也可以是事件屬性聲明 在每種情況中 聲明都可以由屬性集合 new 修飾符 四個訪問修飾符的有效組合 和壹個靜態修飾符組成 壹個事件聲明的類型必須是壹個代表類型 而那個代表類型必須至少同事件本身壹樣可訪問 壹個事件域聲明與壹個聲明了壹個或多個代表類型域的域聲明相應 在壹個事件域聲明中不允許有readonly 修飾符 壹個事件屬性聲明與聲明了壹個代表類型屬性的屬性聲明相應 除了同時包含get訪問符和set訪問符的事件屬性聲明 成員名稱和訪問符聲明對於那些屬性聲明來說都是相同的 並且不允許包含virtual override和abstract 修飾符 在包含壹個事件成員聲明的類或結構的程序文字中 事件成員與代表類型的私有域或屬性相關 而這個成員可以用於任何允許使用域或屬性的上下文中 如果壹個類或結構的程序文字外面包含壹個事件成員聲明 這個事件成員就只能被作為+= 和 = 操作符 (§的右手操作數使用 這些操作符被用來為事件成員附加或去掉事件句柄 而這個事件成員的訪問操作符控制操作在其中被執行的上下文 由於+= 和 = 是唯壹可以在聲明了事件成員的類型外的事件上使用的操作 外部代碼可以為壹個事件添加或去掉句柄 但是不能通過任何其他途徑獲得或修改基本事件域或事件屬性的數值 在例子中 public delegate void EventHandler(object sender Event e);public class Button: Control{ public event EventHandler Click; protected void OnClick(Event e) {if (Click != null) Click(this e); } public void Reset() {Click = null; }}對使用Button類中的Click事件域沒有限制 作為演示的例子 這個域可以在代表調用表達式中被檢驗 修改和使用 類Button中的OnClick方法 引起 Click事件 引起壹個事件的概念與調用由事件成員表示的代表正好相同-因此 對於引起事件沒有特殊的語言構造 註意代表的調用是通過檢查保證代表是非空後才進行的 在類Button的聲明外面 成員Click只能被用在+= 和 = 操作符右手邊 如下 b Click += new EventHandler( );它把壹個代表附加到事件Click的調用列表中 並且 b Click = new EventHandler( );

 它把壹個代表從Click事件的調用列表中刪除 在壹個形式為x += y 或 x = y的操作中 當x是壹個事件成員而引用在包含x的聲明的類型外面發生時 操作的結果就是void(在賦值後與x的數值相反) 這個規則禁止外部代碼直接檢查事件成員的基本代表

 下面的例子介紹了事件句柄如何附加到上面的類Button的實例中

  public class LoginDialog: Form{ Button OkButton; Button CancelButton; public LoginDialog() {OkButton = new Button( );OkButton Click += new EventHandler(OkButtonClick);CancelButton = new Button( );CancelButton Click += new EventHandler(CancelButtonClick); } void OkButtonClick(object sender Event e) {// Handle OkButton Click event } void CancelButtonClick(object sender Event e) {// Handle CancelButton Click event }}這裏 構造函數LoginDialog創建了兩個Button實例 並且把事件句柄附加到事件Click中 事件成員是典型域 就像上面的Button例子中所示 在每個事件消耗壹個域存儲的情況是不可接受的 壹個類可以聲明事件屬性來替代事件域 並且使用私有機制來存儲基本的代表 (設想在某種情況下 大多數事件都是未處理的 每個事件使用壹個域就不能被接受 使用屬性而不是域的能力允許開發人員在空間和時間上面取得壹個折中方案 )在例子中 class Control: Component{ // Unique keys for events static readonly object mouseDownEventKey = new object(); static readonly object mouseUpEventKey = new object(); // Return event handler associated with key protected Delegate GetEventHandler(object key) { } // Set event handler associated with key protected void SetEventHandler(object key Delegate handler) { } // MouseDown event property public event MouseEventHandler MouseDown {get { return (MouseEventHandler)GetEventHandler(mouseDownEventKey);}set { SetEventHandler(mouseDownEventKey value);} } // MouseUp event property public event MouseEventHandler MouseUp {get { return (MouseEventHandler)GetEventHandler(mouseUpEventKey);}set { SetEventHandler(mouseUpEventKey value);}}}

 類Control為事件提供了壹種內部存儲機制 方法SetEventHandler用壹個key來與代表數值相關 而方法GetEventHandler返回與key相關的當前代表 大概基本的存儲機制是按照把空代表類型與key相關不會有消耗而設計的 因此無句柄的事件不占用存儲空間

實例變量初始化函數 當壹個構造函數沒有構造初始化函數或壹個形式為base( )的構造函數初始化函數 構造函數就就隱含的執行被類中聲明的實例域的變量初始化函數指定的初始化 這與賦值序列相關 這些賦值在直接基類構造函數的隱式調用前 在構造函數的入口被直接執行 變量初始化函數按照它們在類聲明中出現的文字順序執行 構造函數執行 可以把壹個實例變量初始化函數和壹個構造函數初始化函數 看作是自動插在構造函數主體中的第壹條語句前 例子

  using System Collections;class A{ int x = y = count; public A() {count = ; } public A(int n) {count = n; }}class B: A{ double sqrt = Math Sqrt( ); ArrayList items = new ArrayList( ); int max; public B(): this( ) {items Add( default ); } public B(int n): base(n ) {max = n; }}

 包含了許多變量初始化函數 並且也包含了每個形式(base和this)的構造函數初始化函數 這個例子與下面介紹的例子相關 在那裏 每條註釋指明了壹個自動插入的語句(自動插入構造函數調用所使用的語法不是有效的 至少用來演示這個機制)

  using System Collections;class A{ int x y count; public A() {x = ; // Variable initializery = ; // Variable initializerobject(); // Invoke object() constructorcount = ; } public A(int n) {x = ; // Variable initializery = ; // Variable initializerobject(); // Invoke object() constructorcount = n; }}class B: A{ double sqrt ; ArrayList items; int max; public B(): this( ) {B( ); // Invoke B(int) constructoritems Add( default ); } public B(int n): base(n ) {sqrt = Math Sqrt( ); // Variable initializeritems = new ArrayList( ); // Variable initializerA(n ); // Invoke A(int) constructormax = n; }}

 註意變量初始化函數被轉換為賦值語句 並且那個賦值語句在對基類構造函數調用前執行 這個順序確保了所有實例域在任何訪問實例的語句執行前 被它們的變量初始化函數初始化 例如

  class A{ public A() {PrintFields(); } public virtual void PrintFields() {}}class B: A{ int x = ; int y; public B() {y = ; } public override void PrintFields() {Console WriteLine( x = { } y = { } x y); }}

 當new B() 被用來創建B的實例時 產生下面的輸出 x = y =

 因為變量初始化函數在基類構造函數被調用前執行 所以x的數值是 可是 y的數值是 (int的默認數值) 這是因為對y的賦值直到基類構造函數返回才被執行 默認構造函數 如果壹個類不包含任何構造函數聲明 就會自動提供壹個默認的構造函數 默認的構造函數通常是下面的形式

  public C(): base() {}

 這裏C是類的名稱 默認構造函數完全調用直接基類的無參數構造函數 如果直接基類中沒有可訪問的無參數構造函數 就會發生錯誤 在例子中

  class Message{ object sender; string text;}

 因為類不包含構造函數聲明 所以提供了壹個默認構造函數 因此 這個例子正好等同於

  class Message{ object sender; string text; public Message(): base() {}}

  私有構造函數 當壹個類只聲明了私有的構造函數時 其他類就不能從這個類派生或創建類的實例 私有構造函數通常用在只包含靜態成員的類中 例如

 public class Trig{private Trig() {} // Prevent instantiationpublic const double PI = ;public static double Sin(double x) { }public static double Cos(double x) { }public static double Tan(double x) { }}

Trig 類提供了壹組相關的方法和常數 但沒有被例示 因此 它聲明了壹個單獨的私有構造函數 註意至少要必須聲明壹個私有構造函數來避免自動生成默認的構造函數(它通常有公***的訪問性) 可選的構造函數參數 構造函數的this( ) 形式通常用於與實現可選的構造函數參數的關聯上 在這個例子中 class Text{ public Text(): this( null) {} public Text(int x int y): this(x y null) {} public Text(int x int y string s) {// Actual constructor implementation }}前兩個構造函數只是為丟失的參數提供了默認的數值 兩個都使用了壹個this( )構造函數的初始化函數來調用第三個構造函數 它實際上做了對新實例進行初始化的工作 效果是那些可選的構造函數參數 Text t = new Text(); // Same as Text( null)Text t = new Text( ); // Same as Text( null)Text t = new Text( Hello ); 析構函數 析構函數是壹個實現破壞壹個類的實例的行為的成員 析構函數使用析構函數聲明來聲明 壹個析構函數聲明的標識符必須為聲明析構函數的類命名 如果指定了任何其他名稱 就會發生壹個錯誤 析構函數聲明的主體指定了為了對類的新實例進行初始化而執行的語句 這於壹個有void返回類型的實例方法的主體相關 例子 class Test{ static void Main() {A F();B F(); }}class A{ static A() {Console WriteLine( Init A ); } public static void F() {Console WriteLine( A F ); }}class B{ static B() {Console WriteLine( Init B ); } public static void F() {Console WriteLine( B F ); }}會產生或者是下面的輸出 Init AA FInit BB F或者是下面的輸出 Init BInit AA FB F lishixinzhi/Article/program/net/201311/12463

  • 上一篇:閥門公司的遊戲掌機被稱為Steam Deck,將於12月發貨
  • 下一篇:華為的壹道面試題目,請幫忙看看
  • copyright 2024編程學習大全網