程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言基礎知識 >> 第五章 類 (2)

第五章 類 (2)

編輯:C語言基礎知識
五章  類 (2)

5.3  類屬性
    有兩種途徑揭示類的命名屬性——通過域成員或者通過屬性。前者是作為具有公共訪問性的成員變量而被實現的;後者並不直接回應存儲位置,只是通過 存取標志(accessors)被訪問。
    當你想讀出或寫入屬性的值時,存取標志限定了被實現的語句。用於讀出屬性的值的存取標志記為關鍵字get,而要修改屬性的值的讀寫符標志記為set。
在你對該理論一知半解以前,請看一下清單5.9中的例子,屬性SquareFeet被標上了get和set的存取標志。
清單 5.9  實現屬性存取標志

1: using System;
2:
3: public class House
4: {
5:  private int m_nSqFeet;
6:
7:  public int SquareFeet
8:  {
9:   get { return m_nSqFeet; }
10:   set { m_nSqFeet = value; }
11:  }
12: }
13:
14: class TestApp
15: {
16:  public static void Main()
17:  {
18:   House myHouse = new House();
19:   myHouse.SquareFeet = 250;
20:   Console.WriteLine(myHouse.SquareFeet);
21:  }
22: }

    House類有一個命名為SquareFeet的屬性,它可以被讀和寫。實際的值存儲在一個可以從類內部訪問的變量中——如果
你想當作一個域成員重寫它,你所要做的就是忽略存取標志而把變量重新定義為:
public int SquareFeet;
對於一個如此簡單的變量,這樣不錯。但是,如果你想要隱藏類內部存儲結構的細節時,就應該采用存取標志。在這種情
況下,set 存取標志給值參數中的屬性傳遞新值。(可以改名,見第10行。)
除了能夠隱藏實現細節外,你還可自由地限定各種操作:
get和set:允許對屬性進行讀寫訪問。
get only:只允許讀屬性的值。
set only:只允許寫屬性的值。
除此之外,你可以獲得實現在set標志中有效代碼的機會。例如,由於種種原因(或根本沒有原因),你就能夠拒絕一個新
值。最好是沒有人告訴你它是一個動態屬性——當你第一次請求它後,它會保存下來,故要盡可能地推遲資源分配。

5.4   索引
   你想過象訪問數組那樣使用索引訪問類嗎 ?使用C#的索引功能,對它的期待便可了結。

語法基本上象這樣:
屬性   修飾符  聲明 { 聲明內容}

具體的例子為
public string this[int nIndex]
{
get { ... }
set { ... }
}

索引返回或按給出的index設置字符串。它沒有屬性,但使用了public修飾符。聲明部分由類型string和this 組成用於表
示類的索引。
get和set的執行規則和屬性的規則相同。(你不能取消其中一個。) 只存在一個差別,那就是:你幾乎可以任意定義大括
弧中的參數。限制為,必須至少規定一個參數,允許ref  和out  修飾符。
this關鍵字確保一個解釋。索引沒有用戶定義的名字,this 表示默認接口的索引。如果類實現了多個接口,你可以增加更
多個由InterfaceName.this說明的索引。

  為了演示一個索引的使用,我創建了一個小型的類,它能夠解析一個主機名為IP地址——或一個IP地址列表(以
http://www.microsoft.com為例 )。這個列表通過索引可以訪問,你可以看一下清單5.10 的具體實現。

清單  5.10  通過一個索引獲取一個IP地址

1: using System;
2: using System.Net;
3:
4: class ResolveDNS
5: {
6:  IPAddress[] m_arrIPs;
7:
8:  public void Resolve(string strHost)
9:  {
10:   IPHostEntry iphe = DNS.GetHostByName(strHost);
11:   m_arrIPs = iphe.AddressList;
12:  }
13:
14:  public IPAddress this[int nIndex]
15:  {
16:   get
17:   {
18:    return m_arrIPs[nIndex];
19:   }
20:  }
21:
22:  public int Count
23:  {
24:   get { return m_arrIPs.Length; }
25:  }
26: }
27:
28: class DNSResolverApp
29: {
30:  public static void Main()
31:  {
32:   ResolveDNS myDNSResolver = new ResolveDNS();
33:   myDNSResolver.Resolve("http://www.microsoft.com");
34:
35:   int nCount = myDNSResolver.Count;
36:   Console.WriteLine("Found {0} IPs for hostname", nCount);
37:   for (int i=0; i < nCount; i++)
38:    Console.WriteLine(myDNSResolver[i]);
39:  }  
40: }

     為了解析主機名,我用到了DNS類,它是System .Net 名字空間的一部分。但是,由於這個名字空間並不包含在核心
庫中,所以必須在編譯命令行中引用該庫:
csc /r:System.Net.dll /out:resolver.exe dnsresolve.cs
     解析代碼是向前解析的。在該  Resolve方法中,代碼調用DNS類的靜態方法GetHostByName,它返回一個IPHostEntry
對象。結果,該對象包含有我要找的數組——AddressList數組。在退出Resolve 方法之前,在局部的對象實例成員
m_arrIPs中,存儲了一個AddressList array的拷貝(類型IPAddress 的對象存儲在其中)。
     具有現在生成的數組 ,通過使用在類ResolveDNS中求得的索引,應用程序代碼就可以在第37至38行列舉出IP地址。
(在第6章 "控制語句",有更多有關語句的信息。)   因為沒有辦法更改IP地址,所以僅給索引使用了get存取標志。為了
簡單其見,我忽略了數組的邊界溢出檢查。
  
5.4  事件
   當你寫一個類時,有時有必要讓類的客戶知道一些已經發生的事件。如果你是一個具有多年編程經驗的程序員,似乎有
很多的解決辦法,包括用於回調的函數指針和用於ActiveX控件的事件接收(event sinks)。現在你將要學到另外一種把客
戶代碼關聯到類通知的辦法——使用事件。
    事件既可以被聲明為類域成員(成員變量),也可以被聲明為屬性。兩者的共性為,事件的類型必定是代表元,而函
數指針原形和C#的代表元具有相同的含義。
    每一個事件都可以被0或更多的客戶占用,且客戶可以隨時關聯或取消事件。你可以以靜態或者以實例方法定義代表
元,而後者很受C++程序員的歡迎。
    既然我已經提到了事件的所有功能及相應的代表元,請看清單5.11中的例子。它生動地體現了該理論。

清單5.11  在類中實現事件處理
1: using System;
2:
3: // 向前聲明
4: public delegate void EventHandler(string strText);
5:
6: class EventSource
7: {
8:  public event EventHandler TextOut;
9:
10:  public void TriggerEvent()
11:  {
12:   if (null != TextOut) TextOut("Event triggered");
13:  }
14: }
15:
16: class TestApp
17: {
18:  public static void Main()
19:  {
20:   EventSource evsrc = new EventSource();
21:   
22:   evsrc.TextOut += new EventHandler(CatchEvent);
23:   evsrc.TriggerEvent();
24:
25:   evsrc.TextOut -= new EventHandler(CatchEvent);
26:   evsrc.TriggerEvent();
27:
28:   TestApp theApp = new TestApp();
29:   evsrc.TextOut += new EventHandler(theApp.InstanceCatch);
30:   evsrc.TriggerEvent();
31:  }
32:
33:  public static void CatchEvent(string strText)
34:  {
35:   Console.WriteLine(strText);
36:  }
37:
38:  public void InstanceCatch(string strText)
39:  {
40:   Console.WriteLine("Instance " + strText);
41:  }
42: }

    第4行聲明了代表元(事件方法原形),它用來給第8行中的EventSource類聲明TextOut事件域成員。你可以觀察到代
表元作為一種新的類型聲明,當聲明事件時可以使用代表元。
    該類僅有一個方法,它允許我們觸發事件。請注意,你必須進行事件域成員不為null的檢測,因為可能會出現沒有客
戶對事件感興趣這種情況。
    TestApp類包含了Main 方法,也包含了另外兩個方法,它們都具備事件所必需的信號。其中一個方法是靜態的,而另
一個是實例方法。
    EventSource 被實例化,而靜態方法CatchEvent被預關聯上了 TextOut事件:
evsrc.TextOut += new EventHandler(Cat
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved