類型與成員基礎(C#)

類型中可包含的成員 :

  • 常量 :數據值恆定不變的符號。(邏輯實質是靜態static成員,所以與類型關聯,不與實例關聯)程序員

  • 字段 :read/write的數據值。編程

  1. 靜態(static)字段 :表示該字段爲類型狀態的一部分。
  2. 非靜態的字段 :表示該字段與實例對象狀態的一部分。
  • 構造器 :將字段初始化爲良好初始狀態的特殊方法。
  1. 實例構造器 :非static構造器,做用於非靜態字段(實例對象字段)。
  2. 類型構造器 :static構造器,做用於靜態字段(類型狀態字段)。
  • 方法 :更改或查詢狀態的函數。(一般要讀寫類型或是對象的字段)
  1. 靜態(static)方法 :做用於類型。
  2. 實例(非靜態)方法 : 做用於所屬類型的實例對象。
  • 操做符重載 :實質是方法,其中定義了當操做符做用於該類型的對象時,應該如何操做該對象。(不是全部編程語言都支持該函數方法,因此非CLS一部分)安全

  • 轉換操做符 :實質是方法,其中定義瞭如何隱式或顯式將類型的對象從一種類型轉型爲另外一種類型的方法。(不是全部編程語言都支持該函數方法,因此非CLS一部分)編程語言

  • 屬性 :屬性容許用簡單的、字段風格的語法設置(set)或查詢(get)類型或對象的邏輯狀態,同時保證狀態不被破壞。(C++中沒有,特別注意)ide

  1. 靜態屬性(static)。
  2. 實例屬性(非static)。
    (屬性基本無參數,有參數及其少見,集合類用的相對較多)
  • 事件 :引起事件一般是爲了響應提供事件的類型或對象的狀態改變,進而向訂閱該事件的對象發送通知。其中包含了兩個方法,容許靜態或實例方法登記或註銷對該事件的訂閱。除了此以外,一般事件一般還用一個委託字段來維護已登記的方法集。
  1. 靜態事件 :容許類型向一個或多個靜態或實例方法發送通知。
  2. 實例事件(非static) :容許實例對象向一個或多個靜態或實例方法發送通知。
  • 類型 :實質是嵌套類型,一般用這個方法將大的、複雜的類型分解成更小的構建單元(building block)來簡化實現。

編譯器會爲上述每種成員都生成 元數據 IL代碼 全部編程語言生成的元數據格式徹底一致,這樣 CLR 才能成爲 公共語言運行時 。)
元數據是全部語言都生成和使用的公共信息,正由於有它,用一種語言寫的代碼才能無縫訪問用另外一種語言寫的代碼, Microsoft.NET Framework 開發平臺的關鍵,實現了編程語言類型和對象的無縫集成。函數

類型成員定義代碼演示 :

using System;

public sealed class SomeType
{
    //嵌套類
    private class SomeNestedType{}
    //常量、只讀和靜態可讀/可寫字段
    private const Int32 c_SomeConstant = 1;
    private readonly String m_SomeReadOnlyField = "2";
    private static Int32 s_SomeReadWriteField = 3;

    //類型構造器
    public SomeType(Int32 x){}
    public SomeType(){}

    //實例方法和靜態方法
    private String InstanceMethod()
    { return null;}
    public static void Main(){}

    //實例屬性
    public Int32 SomeProp
    {
      get{ return 0;}
      set{}
    }

    //實例有參屬性(索引器)
    public Int32 this[String a]
    {
      get{ return 0;}
      set{}
    }

    //實例事件
    public event EventHandler SomeEvent;
}

類型的可見性

友源程序集 :

使用System.Runtime.CompilerServices命名空間中的InternalsVisibleTo特性來標明友源程序集
using System;
using System.Runtime.CompilerServices;

//當前程序集中的internal類型可由如下兩個程序集中的任何代碼訪問(無論什麼版本或語言文化)
[assembly:InternalsVisibleTo("Wintellect, PublicKey = 12345678...90abcdef")]
[assembly:InternalsVisibleTo("Microsoft, PublicKey = b77a5c56...1934e089")]
internal sealed class SomeInternalType {...}
internal sealed class AnotherInternalType {...}
如下代碼展現Wintellect友元程序集如何訪問上述程序集中的internal類型SomeInternalType:
using System;

internal sealed class Foo
{
    private static Object SomeMethod()
    {
      //這個"這個Winteleect"程序集能訪問另外一個程序集的internal類型,就好像那是public訪問限制的。
      SomeInternalType sit = new SomeInternalType();
      return sit;
    }
}

成員的可訪問性

  • private :成員只能由定義類型或任何嵌套類型中的方法訪問。(類中成員不加訪問限制,默認都是private,如非必要都將字段設爲private來確保安全性)性能

  • protected :成員只能由定義類型、任何嵌套類型或者無論在什麼程序集中的派生類型中的方法訪問。(如非必要不要設置,可能會形成類之間的過分耦合和預期以外的結果。)ui

  • internal :成員只能由定義程序集中的方法訪問。this

  • protected internal :成員可由任何嵌套類型任何派生類型無論在什麼程序集中)或者定義程序集中的任何方法訪問。spa

  • public :成員可由任何程序集中的任何方法訪問。(當須要公開類型中的某些方法和字段時使用,儘可能不要使用,不然會形成類型不安全,會被外部操做破壞。)

從基類派生時,只能放寬訪問的限制:如private ——>public,而不能相反收緊限制,由於派生類型必需要可以轉化爲基類型使用多態性))

靜態類

靜態類是永遠不須要實例化的類。
靜態類的限制:
  • 靜態類只能由基類派生。(這意味着靜態類不適用於繼承體系,由於繼承只適用於對象,而不能建立靜態類的實例。)

  • 靜態類不能實現任何接口。(由於只有使用類的實例時,纔可調用類的接口方法,而靜態類不能建立實例。)

  • 靜態類只能定義靜態成員。 (調用靜態構造器對該靜態類初始化。)

  • 靜態類不能做爲字段、方法參數或局部變量使用。(由於它們都表明引用了實例的變量。)

分佈類:

  • partial關鍵字定義,可將類型的代碼分散到多個源代碼文件中,每一個文件均可單獨簽出,多個程序員能同時編輯類型。

組件、多態和版本控制

組件軟件編程(CSP)的特色:
  • 組件(.NET Framework中稱爲程序集)有已經發布的意思。

  • 組件永遠維持本身的標識,.NET中使用動態連接

  • 組件清楚指明它所依賴的組件(引用源數據表)

  • 組件應編檔它的類和成員

  • 組件必須制定它須要的安全權限

  • 組件要發佈在任何「維護版本」中都不會改變的接口

組件關鍵字對組件版本控制的影響:
  • abstract
  1. 用於類型 :表示不能構造該類型的實例(抽象類),同時在該抽象類中,全部方法也都必須聲明爲abstract抽象方法,屬性字段能夠不爲abstract抽象的。
  2. 用於方法 :表示爲了構造派生類型的實例,派生類型必須重寫並實現這個成員。(成員方法能夠只有聲明無主體。)
  • virtual虛函數聲明,不可用於類型,只能用於方法成員,表示該成員可由派生類型重寫(不強制重寫區別於abstract,成員方法不能只聲明,要有主體實現。)
    虛函數調用性能很低,同時由於它會放棄不少控制,喪失獨立性,應該是不得已的選擇。

  • override :只能用於方法成員,表示派生類型正在重寫基類型的成員。

  • sealed密封

  1. 用於類型:表示該類型不能用做基類型。(製造密封類)
  2. 用於成員 :表示這個成員不能被派生類型重寫,只能將該關鍵字應用於重寫虛方法的方法。
  • new :應用於嵌套類型、方法、屬性、事件、常量或字段時,表示該成員與基類中類似的成員無任何關係。

CLR如何調用虛方法、屬性和事件

該部分須要之後開發經驗豐富再回顧:
CLR(IL代碼)提供兩個方法調用指令:
  • call :可調用靜態方法、實例方法和虛方法。該指令常常用於以非虛方式調用虛方法。
  • callvirt :可調用實例方法和虛方法。會驗證調用的變量是否爲null,因此執行速度比call指令稍慢。
該部分提煉經驗以下:
  • 由於調用虛方法性能太低,設計類型時應儘可能減小虛方法數量。
  • 設計基類時,一般須要提供一組重載的簡便方法。爲了提升性能,應該使最複雜的方法成爲虛函數,全部重載簡便方法成爲非虛的方法。

定義類時統一遵循的原則:

  • 設計類時,應該優先顯式地將其設爲密封類(sealed)這樣作:
  1. 便於版本控制 :由於最初密封,未來能夠在不破壞兼容性前提下改成非密封,而最初非密封,未來改成密封類可能出現未知的錯誤。
  2. 可使用非虛方式調用虛方法 :由於密封類不會有派生類。
  3. 保護本身的狀態不容許外界破壞
  • 數據字段應該優先設爲private,儘可能少用protected、internal、public。由於狀態一旦公開,就很容易產生問題,形成對象的行爲沒法預測,留下未知或是嚴重的安全隱患。

  • 類的內部設計中,應儘可能將方法、屬性和事件定義爲private和非虛的。只有在須要公開類型的某些功能時,纔會將對應成員設爲public,以便公開給外界使用,protected和internal是次級選擇,virtual永遠是最後才考慮的,虛方法會放棄不少控制,喪失獨立性。

  • 若是類型要做爲基類型使用,增長或是修改它的成員必須很是當心。

使用new關鍵字聲明:
namespace CompanyA
{ 
  public class Phone
  {
    public void Dial()
    {
      Console.WriteLine("Phone.Dial");
      EstablishConnection();    //在這裏進行撥號操做
    }
    protected virtual void EstablishConnection()
    {
      Console.WriteLine("Phone.EstablishConnection");    //在這裏執行創建鏈接的操做
    }
  }
}

namespace CompanyB
{
  public class BetterPhone : CompanyA.Phone
  {
    //保留關鍵字new,指明該方法與基類型中的Dial方法沒有關係。
    public new void Dial()
    {
      Console.WriteLine("BetterPhone.Dial");
      EstablishConnection();
      base.Dial();
    }
    
    //爲這個方法添加關鍵字new,指明該方法與基類型的EstablishConnection方法沒有關係。
    protected new virtual void EstablishConnection()
    {
      Console.WriteLine("BetterPhone.EstablishConnection");    //在這裏執行創建鏈接的操做。
    }
  }
}
代碼輸出結果以下所示:

BetterPhone.Dial BetterPhone.EstablishConnection Phone.Dial Phone.EstablishConnection

相關文章
相關標籤/搜索