程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 基礎-CLR-從“類”說開來【1】

C# 基礎-CLR-從“類”說開來【1】

編輯:C#入門知識

 

上篇談了CLR支持的兩種類型:reference-type 和value-type,這篇來詳細談談類(class)。  

  類(class) 是最基礎的C# 類型。類是一個數據結構,將狀態(字段)和操作(方法和其他函數成員)組合在一個單元中。類為動態創建的類實例(instance) 提供了定義,實例也稱為對象(object)。類支持繼承(inheritance) 和多態性(polymorphism),這是派生類(derived class) 可用來擴展和專用化基類(base class) 的機制。類的實例使用new運算符創建,該運算符為新的實例分配內存、調用構造函數初始化該實例,並返回對該實例的引用。當不再使用對象時,該對象占用的內存將自動收回。在C# 中,沒有必要也不可能顯式釋放分配給對象的內存。

      類包可以包含一下成員:     (靜態成員(static member),或者是實例成員(instance member)。靜態成員屬於類,實例成員屬於該類的實例)  

成員

說明

常量

與類關聯的常量值

字段

類的變量

方法

類可執行的計算和操作

屬性

與讀寫類的命名屬性相關聯的操作

索引器

與以數組方式索引類的實例相關聯的操作

事件

可由類生成的通知

運算符

類所支持的轉換和表達式運算符

構造函數

初始化類的實例或類本身所需的操作

析構函數

在永久丟棄類的實例之前執行的操作

類型

類所聲明的嵌套類型

 

 看下面例子:

public sealed class SomeType
{ // 1
// 嵌套類
private class SomeNestedType { } // 2
// 常量,只讀字段,靜態字段
private const Int32 c_SomeConstant = 1; // 3
private readonly String m_SomeReadOnlyField = "2"; // 4
private static Int32 s_SomeReadWriteField = 3; // 5
// 類型構造器
static SomeType() { } // 6
// 實例構造器
public SomeType() { } // 7
public SomeType(Int32 x) { } // 8
// 靜態方法和類型方法
public static void Main() { } // 9
public String InstanceMethod() { return null; } // 10
// 實例屬性
public Int32 SomeProp
{ // 11
get { return 0; } // 12
set { } // 13
}
// 有參索引器
public Int32 this[String s]
{ // 14
get { return 0; } // 15
set { } // 16
}
// 實例事件
public event EventHandler SomeEvent; // 17
}      類型成員的可訪問性   CLR術語 C#術語 含義 public public

訪問不受限制

Family or Assembly protected internal

訪問僅限於此程序或從此類派生的類

Assembly internal

訪問僅限於此程序

Family and Assembly 不支持   Family     protected

訪問僅限於此類或從此類派生的類

Private private

訪問僅限於此類

         

靜態類

  static只能用於類,不能用於結構,因為CLR總是允許值類型實例化,無法阻止。   C#編譯器對靜態類型進行了如下的限制:  
  • 靜態類必須直接從System.Object派生,從其他任何基類派生都沒有任何意義
  • 靜態類不能實現任何接口,這是因為只有使用了類的一個實例,才可以調用類的接口方法
  • 靜態類只能定義靜態成員(字段、方法、屬性和事件),任何實例成員都將導致編譯錯誤
  • 靜態類不能作為字段、方法參數或者局部變量使用,這些玩意都是實例的變量,編譯器會報錯
public static class MyStatic
{
/// <summary>
/// 靜態字段
/// </summary>
private static string staticString = "Hello bangq";
/// <summary>
/// 靜態屬性
/// </summary>
public static string StaticString
{
        get { return staticString; }
        set { staticString = value; }
}
/// <summary>
/// 靜態方法
/// </summary>
public static void SayHello()
{
    Console.WriteLine(staticString);
}
}
  staticvoidMain(string[] args) {   MyStatic.SayHello();//Hello bangq   MyStatic.StaticString = "你好 BangQ ";   Console.WriteLine(MyStatic.StaticString);//你好 BangQ   Console.ReadKey(); } 可以這樣說,靜態類是MonoState模式的一種體現。提到MonoState就不得不提Singleton(單例)模式。     classSingleton {     ///<summary>     ///靜態成員     ///</summary>     private static Singleton _instance = null;     ///<summary>     ///靜態屬性     ///</summary>     public static Singleton Instance {         get {             if (_instance == null)                 {                     _instance = new Singleton();                 }                   return _instance;              }         }     private Singleton() { }//私有的構造函數       public void SayHello()         {             Console.WriteLine("hello bangq"); www.2cto.com         }   } 單例模式可以保證系統中只有一個對象的實例,通常情況下可以通過 一個靜態成員、一個靜態屬性或方法、一個私有構造函數來實現。 為了保證系統中只有一個實例,所以在單例模式中將構造函數設置成私有的,這樣就不能New一個實例了,必須通過獲取實例的屬性或者方法。所以當出現這種代碼時:Singletonsingleton = new Singleton();編譯器會報以下錯誤: ConsoleAppDemo.Singleton.Singleton()' is inaccessible due to its protection level  如果仔細的看了上面Singleton的代碼可以發現,上述代碼如果在多線程的情況下可能會創建多個實例,如:兩個線程都執行到了 if(_instance == null),那麼第一個線程創建了一個實例,第二個線程又創建了一個實例。關於多線程的問題,在以後會做總結,這裡只簡單說一下,加個鎖就ok了。調整後的代碼如下。       ///<summary>     ///鎖     ///</summary>     private static readonly object _lock = new object();     ///<summary>     ///靜態屬性     ///</summary>     public static Singleton Instance {         get {                 if (_instance == null)                 {                     lock (_lock)                         {                             if (_instance == null)                             {                                 _instance = new Singleton();                             }                           }                   }               return _instance;             }     }   這個裡面還有很多技巧和可以優化的地方,可以參見博客園兄弟的文章:http://www.cnblogs.com/BoyXiao/archive/2010/05/07/1729376.html  

下面再來說下Monostate 模式

 

publicclassSayHello{privatestringhelloString ="hello wordh";publicSayHello(stringmessage){this.helloString =message;}publicstringHelloString{get {returnhelloString;}set{this.helloString =value;}}}publicclassMonoState{privatestaticSayHelloHello;publicMonoState(){Hello=newSayHello("Hello Word");}publicSayHelloSay{get {returnHello;}set{Hello=value;}}}

 

mian函數裡面的內容

monostate.Say.HelloString = "你好,BangQ";

Monostate是另一種獲得“系統某個類別對象都表現為一個對象”的實現方式,Singleton模式重在通過保證系統中只有唯一實例,而Monostate模式重在保證唯一狀態, 當然Singleton模式更多的是用來 保證唯一實例。Monostate模式更多關注的是行為,即行為上的一致;Singleton模式更多關注的是結構,強制結構上的單一,僅產生唯一實例.關於設計模式方面內容以後有機會再詳細講,再回到類的成員上來。

 

常量和字段

  在C#中使用const定義常量,由於常量的值不會變化,所以常量總是被視為類型定義的一部分,常量總是被視為靜態成員而不是實例成員。常量的值必須是在編譯時確定的。代碼引用一個常量時,直接提取常量的值,嵌入到生成的IL代碼中,所以在運行時不需要為常量分配任何內存。不能獲取常量的地址,也不能以引用的方式傳遞常量。CLR via C# 裡面的例子:   usingSystem;   publicsealedclassSomeLibraryType {     public const Int32 MaxEntriesInList = 50; }   classProgram {     static void Main(string[] args)     {         Console.WriteLine(SomeLibraryType.MaxEntriesInList)       } } 使用ILSpy可以看到 這行代碼IL_0XXX: ldc.i4.s 50 證明了上述所說,const直接嵌入到IL代碼裡面   【注意:常量不能定義為Static,因為常量總是隱式為static】   一個程序集A定義了一個常量,程序集B引用了這個常量,當程序集A中的常量發生更改時,只有B程序集重新編譯才能使新的常量生效。如果想要在運行時獲取一個常量,建議使用只讀的字段。   字段(field)是一種數據成員,其中容納了一個值類型的實例或者是一個引用類型的引用。下表總結了字段的修飾符。   CLR術語 C#術語 說明 Static static 類狀態的一部分,而不是實例狀態的一部分 InitOnly readonly 只能由構造器方法中的代碼寫入 Volatile volatile 編譯器,CLR或硬件不會執行一些“線程不安全”的優化措施。     readonly也可以定義系統中恆定不變的量。和const不同的是,readonly指定初始值後可以構造函數中更改。readonly的值也可以通過別的手段去更改,比如反射。小結一下:const是編譯是常量,readonly是運行時常量。const比較高效,上面說了,無需分配內存。推薦使用static readonly 代替const。   本來想總結下類的其他成員,發現篇幅有點超了,下篇在寫吧

 

作者 BangQ

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved