日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

4.类型设计规范《.NET设计规范》

發布時間:2024/4/17 asp.net 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 4.类型设计规范《.NET设计规范》 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

類是引用類型的一般情況,占了框架中的大多情況,類的流行歸于它支持面向對象的特征,以及它的普遍的適用性,基類和抽象類是兩個特殊的邏輯分組,它們與擴張性有關。

由于CLR不支持多繼承,接口類型可以用來模擬多繼承,既能被引用類型實現,也能被值類型實現。

結構是值類型的一般情況,應該用于小而簡單的類型,就像編程語言的基本類型一樣。

枚舉是值類型的一個特例,它用來定義一小組值。

靜態類是那些用來容納靜態成員的類型,常用來提供對其他操作的快速訪問。

委托、異常、Attribute、數據、集合都是引用類型的特例,各有各自的用途。

  • √ 要 確保每個類型由一組定義明確、相互關聯的成員組成,而不要僅僅是一些無關功能的隨機集合。

4.1.類型和名字空間

在設計大型框架之前,應該決定如何將功能劃分到一組功能域中,這些功能域由名字空間表示,為了確保一組有條理的名字空間包含的類型能很好的集成,不發生沖突,以及不會重復,自頂向下的設計很有必要。導致了下面的規范:

  • √ 要 用名字空間把類型組織成一個相關的特性域的層次結構。
  • × 避免 非常深的名字空間層次(難于瀏覽,需要經常回溯)
  • × 避免 有太多的名字空間
  • × 避免 把為高級方案而設計的類型和常見的編程任務而設計的類型放在同一個名字空間中。
    (方便用戶更容易理解框架的基本概念,而且更容易在常見的場景中使用框架)
  • × 不要 不指定類型的名字空間就定義類型。

標準子名字空間的命名

很少使用的類型應該放在子名字空間中,以免擾亂主名字空間,我們確定了幾組類型,應該把它們從主名字空間中區分離出來。

  • .Design 子名字空間
    僅用于設計時的類型應該放在名為 .Design 的子名字空間。
    如:System.Windows.Forms.Design;
    System.Messaging.Design;
  • .Permissions子名字空間
    權限類型應該放在 .Permissions 子名字空間。
  • .Interop子命名空間
    許多框架需要支持與舊系統的互操作性(interoperability)。
  • 4.2 類和結構之間的選擇

    引用類型在堆上分配,由垃圾收集器管理;而值類型要么在棧上分配并在棧展開時釋放,要么內聯在容納它的類型中并在容納它的類型被釋放時釋放。因此,與引用類型的分配與釋放相比,值類型的分配與釋放開銷更低。

    引用類型的數組不是非內聯分配的,意為數組元素只是一些引用,指向那些位于堆中的引用類型的實例。而值類型的分配是內聯的,數組的元素就是值類型的真正實例。因此值類型的分配和釋放的開銷要比引用類型的大的多,在大多情況下,值類型數組具有更好的局部性。

    值類型在被強制轉換為對象或裝箱。因為裝箱和對象是在堆上分配的,且由垃圾收集器管理,所以太多的裝拆箱操作會對堆、垃圾收集器,并對系統性能造成影響。相比之下,在對引用類型執行轉換操作,不會發生裝箱操作。

    引用類型的賦值是復制引用,而值類型的賦值復制整個值,對大的引用類型復制開銷要比值類型小的多

    引用類型是引用傳遞,值類型是值傳遞。改變引用類型的一個實例會影響其他的實例,改變值類型的實例,不會影響到它的副本。

    框架中的大多數類型應該是類,但是在某些特殊情況下,由于值類型所具有的特征,使用結構更合適。

    • √ 考慮 定義結構而不是類 —— 如果該類型的實例比較小,生命周期比較短,經常被內嵌在其他對象中。
    • × 避免 定義結構,除非該類型具有以下特征:

      • 它在邏輯上代表一個獨立的值,與基本類型相似(int)

      • 它的實例大小小于16字節

      • 它是不可變的

      • 它不需要被經常裝箱

    在所有的其他情況下,應該將類型定義為類。

    4.3 類和接口之間的選擇

    一般來說,類是用來暴露抽象的優先選擇。

      接口的缺點在于當需要允許API不斷演化時,它的靈活性不如類,一旦你發布了一個接口,它的成員就永遠固定了,給接口添加任何東西都會破壞已經實現該接口的已有類型。

      類提供了更多的靈活性,你可以給一個已發布的類添加成員。只要添加的方法不是抽象的,任何已有的派生類無需改變仍能繼續使用。

    • √ 要 優先采用類而不是接口
      與基于接口的API相比,基于類的API容易演化得多,因為可以給類型添加成員而不會破壞已有的代碼。

    • √ 要 用抽象類而不是接口來解除協定與實現之間的耦合。
      抽象類經過正確的設計,同樣能夠解除協定與實現之間的耦合,與接口能達到的程度不相上下。

    • √ 要 定義接口,如果需要提供一個多態的值類型層次結構的話。
      值類型不能自其它類型繼承,但是她們可以實現接口。
    public struct Int32 : IComparable,IFormattable,IConvertible {...}
    • √ 考慮 通過定義接口來達到與多重繼承相類似的效果。

    4.4 抽象類的設計

    • × 不要 在抽象類型中定義公有的或內部受保護的構造函數。
      只有當用戶需要創建一個類型的實例時,該類型的構造參數才是公有的,由于你無法創建一個抽象類的實例,因此如果抽象類型具有公有構造函數,那么這樣的設計不僅錯誤,而且會誤導用戶。
    //錯誤設計 public abstract class Claim {public Claim(){} } //好設計 public abstract class Claim {protected Claim(){} }
    • √ 要 為抽象類定義受保護的構造函數或內部構造函數。
      更常見的情況是受保護的構造函數,唯一的目的是允許子類型被創建時,基類能夠做自己的初始化。
    public abstract class Claim {protected Claim(){...} }

    內部構造函數可以用來把該抽象類的具體實現限制在定義該抽象類的程序集中。

    public abstract class Claim {internal Claim(){...} }
    • √ 要 為發布的抽象類提供至少一個繼承自該類的具體類型。
      這有助于驗證該抽象類的設計是否正確。例如,System.IO.FileStream 是 System.IO.FileStream 抽象類的一個實現。

    4.5 靜態類的設計

    靜態類定義為一個只包含靜態成員的類。
    如果一個類被定義為靜態,那么它就是密封的、抽象的,不能覆蓋或者聲明任何實例成員。
      靜態類是在純面向對象設計和簡單性之間的一個權衡,它們被廣泛用來提供一下訪問其他操作(比如System.IO.File)的快捷方式,存放擴展方法,或者以一種不完全面向對象的方式來提供一些功能。(System.Enviroment)

    • √ 要 盡量少用靜態類
      靜態類僅被用作輔助類,來支持框架的面向對象的核心。

    • × 不要 把靜態類當做雜物箱。
      每一個靜態類都應該有其明確的目的。

    • × 不要 聲明或覆蓋(override)靜態類中的實例成員。

    • √ 要 把靜態類定義為密封的、抽象的,并添加一個私有的實例構造函數。

    4.6 接口的設計

    雖然大多數情況下API用類或結構來構建最好,但是在有些情況下,接口更合適。甚至某些情況接口是唯一的選擇。
      CLR 不支持多繼承,但允許類型實現一個或多個接口,因此通常用接口來實現多繼承。
      另一種適合定義接口的情況是,為多種類型(包括值類型)創建一個公共接口。雖然值類型無法繼承除了 System.ValueType 之外的其他類型,但他們可以實現接口,所以提供了一個公共的基類型,使用接口是唯一的選擇。

    public struct Boolean : IComparable {...}
    • √ 要 定義接口,如果你需要包括值類型在內的一組類型支持一些公共的API。

    • √ 考慮 定義接口,如果需要讓已經繼承自其它類型的類型支持該接口提供的功能。

    • × 避免 使用記號接口(沒有成員的接口)
    //避免 public interface IImmutable {} //空接口 public class Key : IImmutable{...} //考慮 [IImmutable] public class Key{...}
    • √ 要 為接口提供至少一個實現該接口的類型。

    • √ 要 為你定義的每個接口提供至少一個使用該接口的API(一個以接口為參數的方法或是一個類型為該接口的屬性)
      例如,List<T>.Sort 使用了 IComparer<T> 接口。

    • × 不要 給已發行的接口再添加成員。
      這樣做會破壞該接口的實現,為了避免版本的問題,應該創建一個新的接口。
      一般來說,在為托管代碼設計可重用的程序庫時,你應該選擇類而不是接口。

    4.7 結構的設計

    通用目的的值類型通常稱為 struct(結構)。

    • × 不要 為結構提供默認的構造函數。(C#不允許結構有默認的構造函數)

    • × 不要 定義可變的值類型。

    • √ 要 確保所有的實例數據都為0,false,或null時,結構仍處于有效狀態。(可以防止在創建一個結構時創建出無效的實例)

    • √ 要 為值類型實現 IEquatable<T>。
      值類型的 Object.Equals 方法會導致裝箱,默認的實現并不高效,因為使用了反射,IEquatable<T>.Equals 性能好的多,不會導致裝箱。

    • × 不要 顯示的擴展 System.ValueType,實施上大多數編程語言步允許這么做。

    4.8 枚舉的設計

    枚舉是一種特殊的值類型,有兩種類型的枚舉:簡單枚舉 和 標記枚舉(flag enum)。

    簡單枚舉 代表小型的、閉合的一組選擇。例如(一組顏色):

    Public enumColor{ Red, Green, Blue, …… }

    標記枚舉 的設計是為了支持對枚舉值進行按位操作。標記枚舉的常見例子是一個選擇列表,

    [Flags] Public enumAttributeTargets {Assembly=0x0001,Module=0x0002,Cass=0x0004,Struct=0x0008 }
    • √ 要 用枚舉來加強那些表示值的集合的參數、屬性以及返回值的類型性。

    • √ 要 優先使用枚舉而不要使用靜態常量。(枚舉是一個包含一組靜態常量的結構)

    • × 不要 把枚舉用于開放的集合(比如操作系統版本、朋友的名字等)

    • × 不要 提供為了今后使用而保留的枚舉值。

    • × 避免 顯示的暴露只有一個值的枚舉。

    • × 不要 把 sentinel 值包含在枚舉值中。

    • √ 要 為簡單枚舉類型提供零值。(應該考慮把該值稱為 None 之類的東西,如果這樣的值不適合用于某個特定的枚舉,那么應該把該枚舉中最常用的默認值賦值為0)
    public enum Compression{None = 0,Gzip,Deflate, }
    • √ 考慮 以 Int32 作為枚舉的基本實現類型。

    • √ 要 用復數名詞或者名詞短語來命名標記枚舉,用單數名詞或者名詞短語來命名簡單枚舉。

    • × 不要 直接擴充 System.Enum。
      System.Enum 是一個特殊的類型,被 CLR 用來創建用戶定義的枚舉。

    4.8.1 標記枚舉的設計

    • √ 要 對標記枚舉使用 System.FlagsAttribute,不要把該 attribute 用于簡單枚舉。
    [Flags] Public enum AttributeTargets {...}
    • √ 要 用2的冪次方作為標記枚舉的值,這樣就可以通過按位或操作自由組合他們。
    [Flags] Public enum WatcherChangeTypes {Created=0x0002,Deleted=0x0004,Changed=0x0008,Renamed=0x00010, }
    • √ 考慮 為常用的標記組合提供特殊的枚舉值。
      位操作是一個高級概念,對應簡單任務來說不是必須的,FileAccess.ReadWrite 就是這樣一個例子
    [Flags] Public enum FileAccess {Read=1,Write=2,ReadWrite= Read | Write, }
    • × 避免 讓創建的標記枚舉包含某些無效的組合。

    • × 避免 把0用作標記枚舉的值,除非該值表示“所有標記都被清除“,而且按下一條規范進行了適當的命名。

      C#中字面常量0可以隱式地轉換為任何枚舉類型,因此你可以編寫這樣的代碼:

      if (Foo.SomeFlag == 0) ...

      CLR規定任何值類型的默認值“所有的位都清零“。

    • √ 要 把標記枚舉的零值命名為 None,對其標枚舉來說,該值必須始終意味著“所有標記均被清除”。
    [Flags] Public enum BorderStyle {Fixed3D=0x1,FixedSingle=0x2,None=0x0 } if(foo.BorderStyle == BorderStyle.None) ...

    但是,該規則只適用于標記枚舉,對于非標記枚舉的情況,避免使用0值實際上是不利的,所有的枚舉類型一開始都為零值。

    4.8.2 給枚舉添加值

    常會發現在需要在程序發行之后需要給一個枚舉添加值。如果新添加的值是一個已有API的返回值,那么就存在潛在的應用程序兼容性問題。

    • √ 考慮 給枚舉添加值,盡管有那么一點兼容性的風險。

    如果有實際數據,表明給枚舉添加值會導致應用程序的不兼容,可以考慮添加一個新的API來返回新老枚舉值,這樣就能確保仍然兼容現有的應用程序。

    4.9 嵌套類型

    嵌套類型是一個定義在另一個類型的作用域內的類型。另一個類型被稱為外層類型。嵌套類型能夠訪問外層類型的所有成員。可以訪問定義在外層類型的私有字段以及定義在外層類型的所有父類的受保護字段。

      一般來說,盡量少用嵌套類型,嵌套類型與外層類型緊密耦合,不適合將它們作為通用類型。嵌套類型適合用來對它們的外層類型的實現細節建模。

    • √ 要 在想讓一個類型能夠訪問外層類型的成員時才使用嵌套類型。

    • × 不要 用嵌套類型進行邏輯分組,應該用名字空間來達到此目的。

    • × 避免 公開的暴露嵌套類型,唯一的例外是如果只需要在極少數的場景中聲明嵌套類型的變量,比如派生子類,或者其他高級自定義場景中。
      一般避免使用嵌套類型,只有在開發人員幾乎不需要聲明該類型的變量時才使用嵌套類型。(例如集合的枚舉器)

    • × 不要 使用嵌套類型,如果該類型可能會被除了它的外層類型之外的類型引用。

    • × 不要 使用嵌套類型,如果它們需要被客戶代碼實例化。

    • × 不要 把嵌套類型定義為接口的成員。

    一般來說盡量少用嵌套類型,而且應該避免將嵌套類型公開暴露給外界。

    轉載于:https://www.cnblogs.com/tangge/p/6851477.html

    總結

    以上是生活随笔為你收集整理的4.类型设计规范《.NET设计规范》的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。