結構在以下幾個重要方面與類不同:
— 結構是值型別(參見11.3.1小節)。
— 所有結構型別都隱式地繼承自類system.valuetype(參見11.3.2小節)。
— 對結構型別的變數進行賦值,將建立所賦的值的乙個「副本」(參見11.3.3小節)。
— 結構的預設值的生成方式為:將所有值型別的域設定為它們的預設值,並將所有引用型別的域設定為null(參見11.3.4小節)。
— 使用裝箱和拆箱操作在結構型別和object之間進行轉換(參見11.3.5小節)。
— 對於結構,this具有不同的意義(參見11.3.6小節)。
— 結構的例項域宣告不能包含變數初始值設定項(參見11.3.7小節)。
— 結構不能宣告無引數的例項建構函式(參見11.3.8小節)。
— 結構不能宣告析構函式(參見11.3.9小節)。
結構是值型別(參見4.1節),並且被稱為具有值語 義。另一方面,類是引用型別(參見4.2節),並且被稱為具有引用語義。
結構型別的變數直接包含了結構的資料,而類型別的變數只包含 了對資料的引用(稱為「物件」)。如果結構b包含乙個型別為a的例項域,並且a為結構型別,則如果a依賴於b,將發生編譯時錯誤。如果結構x包含乙個型別 為y的例項域,則結構x直接依賴於結構y。從這個定義可以推斷出,乙個結構所依賴的結構的完整集合就是此直接依賴於關係的傳遞閉包。例如:
struct node
是錯誤的,因為node包含了乙個其自身型別的例項域。另乙個示例:
struct a
struct b
struct c
也是錯誤的,因為型別a、b和c彼此相互依賴。
對於 類,兩個變數可能會引用同乙個物件,因此對乙個變數進行的操作可能會影響另乙個變數所引用的物件。對於結構,每個變數都具有其自己的資料副本(ref和 out引數變數除外),因此對乙個變數的操作不會影響其他變數。另外,由於結構不是引用型別,因此結構型別的值不可能為null。
給定以下宣告:
struct point
}以下**片段將輸出值10:
point a = new point(10, 10);
point b = a;
a.x = 100;
system.console.writeline(b.x);
將a賦給b將建立該值的乙個副本,因此b不會受到對a.x進 行的賦值的影響。如果將point宣告為類,則由於a和b將引用同乙個物件,因此輸出將為100。
所有的結構型別都隱式地繼承自類 system.valuetype,而後者則繼承自object類。結構宣告可以指定乙個實現介面的列表,但是不能指定基類。
結構型別永遠不會是抽象的,並且始終是隱式密封的。 因此在結構宣告中不允許使用abstract和sealed修飾符。
由於結構不支援繼承,所以結構成員的宣告可訪問性不 能是protected或protected internal。
結構中的函式成員不能是abstract或 virtual,因而override修飾符只允許用於重寫繼承自system.valuetype的方法。
對結構型別變數的賦值將建立乙個所賦值的「副本」。 這不同於對類型別變數的賦值,後者複製的是引用,而不是由引用所標識的物件。
與賦值類似,將結構作為值引數傳遞或者作為函式成員 的結果返回時,將建立該結構的乙個副本。結構可通過ref或out引數以引用方式傳遞給函式成員。
當結構的屬性或索引器是賦值的目標時,與屬性或索引 器訪問相關聯的例項表示式必須歸類為乙個變數。如果該例項表示式歸類為乙個值,則將發生編譯時錯誤。7.13.1小節對此進行了詳細的說明。
如5.2節所述,有幾種變數在建立時將自動初始化為 它們的預設值。對於類型別和其他引用型別的變數,此預設值為null。但是,由於結構是不能為null的值型別,因此結構的預設值,是通過將所有值型別域 設定為它們的預設值,並將所有引用型別域設定為null而產生的值。
對於上面示例中所宣告的point結構,示例:
point a=new point[100];
會將陣列中的每個point初始化為通過將x和y域設定為零而產生的值。
乙個結構的預設值對應於該結構的預設建構函式所返回 的值(參見4.1.1小節)。與類不同,結構不允許宣告無引數的例項建構函式。相反,每個結構都隱式地具有乙個無引數的例項建構函式,該建構函式總是返回 通過將所有值型別的域設定為它們的預設值,並將所有引用型別的域設定為null而得到的值。
在設計結構時,要設法確保其預設初始化狀態是有效的狀態。在下面的示例中:
using system;
struct keyvaluepair
}除非在顯式呼叫時,否則使用者自定義的例項建構函式不允許出現null值。在變數keyvaluepair可能會被初始化為 它的預設值的情況下,key和value域都將為null,所以設計該結構時,必須正確處理好此問題。
類型別的值可以轉換為object型別或由該類實現 的介面型別,這只需在編譯時將對應的引用當作另乙個型別處理即可。與此類似,object型別的值或介面型別的值也可以轉換回類型別,而不必更改相應的引 用。當然,在這種情況下,需要進行執行時型別檢查。
由於結構不是引用型別,因此上述操作對結構型別是以 不同的方式實現的。當結構型別的值轉換為object型別或乙個由該結構實現的介面型別時,將會執行一次裝箱操作。與此類似,當object型別的值或接 口型別的值轉換回結構型別時,將會執行一次拆箱操作。與對類型別進行的相同操作相比,主要區別在於:裝箱操作會把相關的結構值複製為乙個已裝箱的例項,而 拆箱則會從已裝箱的例項中複製出乙個結構值。因此,在進行裝箱或拆箱操作之後,對未裝箱的結構所進行的更改不會影響已裝箱的結構。
有關裝箱和拆箱的詳細資訊,請參見4.3節。
在類的例項建構函式或例項函式成員中,this歸類 為乙個值。因此,雖然this可以用於引用為其呼叫函式成員的例項,但是不能在類的函式成員中對this進行賦值。
在結構 的例項建構函式內,this對應於乙個結構型別的out引數,而在結構的例項函式成員內,this對應於乙個結構型別的ref引數。在這兩種情況 下,this都將歸類為乙個變數,因此可以通過對this進行賦值,或通過將this作為ref或out引數進行傳遞,而對為其呼叫函式成員的整個結構進 行修改。
如 11.3.4小節所述,結構的預設值由將所有值型別的域設定為它們的預設值並將所有引用型別的域設定為null而產生的值組成。由於這個原因,結構不允許 它的例項域宣告包含變數初始值設定項。此限制只適用於例項域。結構的靜態域宣告可以包含變數初始值設定項。
示例:struct point
將出現錯誤,因為例項域宣告中包含了變數初始值設定項。
與類不同,結構不允許宣告無引數的例項建構函式。相反,每個 結構都隱式地包含乙個無引數的例項建構函式,該建構函式總是返回通過將所有值型別的域設定為它們的預設值,並將所有引用型別的域設定為null而得到的值 (參見4.1.2小節)。結構可以宣告具有引數的例項建構函式。例如:
struct point
}給定以上宣告, 語句:
point p1 = new point();
point p2 = new point(0, 0);
都將建立乙個x和y都初始化為零的point。
結構的例項建構函式不能包含形式為 「base(…)」的建構函式初始值設定項。
如果結構的例項建構函式沒有指定建構函式初始值設定項,則this變數將相當於乙個結構型別的out引數,並且與out參 數類似,this必須在該結構函式返回的每個位置都已明確賦值(參見5.3節)。如果結構的例項建構函式指定了乙個建構函式初始值設定項,則this變數 將相當於乙個結構型別的ref引數,並且與ref引數類似,this將被視為在進入建構函式主體時已明確賦值。在下面的例項建構函式實現中:
struct point
}public int y
}public point(int x, int y)
}在被構造的結構的所有域都已明確賦值之前,不能呼叫任何例項成員函式(包括屬性x和y的set訪問器)。但是請注意,如果 point是類而不是結構,則允許上述的例項建構函式。
結構不允許宣告析構函式。
結構的靜態建構函式與類的靜態建構函式所遵循的規則 大體相同。在應用程式域中第一次發生以下事件時,將觸發結構的靜態建構函式的執行:
— 結構的例項成員被引用。
— 結構的靜態成員被引用。
— 結構的顯式宣告的建構函式被呼叫。
建立結構型別的預設值(參見11.3.4小節)不會 觸發靜態建構函式(例如陣列中元素的初始值)。
類和結構的區別?
類 類是引用型別在堆上分配,類的例項進行賦值只是複製了引用,都指向同一段實際物件分配的記憶體 類有構造和析構函式 類可以繼承和被繼承 結構 結構是值型別在棧上分配 雖然棧的訪問速度比較堆要快,但棧的資源有限放 結構的賦值將分配產生乙個新的物件。結構沒有建構函式,但可以新增。結構沒有析構函式 結構不可...
結構和類的區別
類是引用型別,是儲存在託管堆中的。通過定義類,我們可以在資料的生存期上得到很高的靈活性,但是也會讓程式的效能有一定的損失。雖然這種損失很小,但當我們只需要定義乙個很小的結構時,用類來定義就有些浪費,對於這樣的問題,c 有相對應的方案來解決,那就是 結構 struct 結構與類的區別 1 結構是值型別...
類和結構的區別?
靜態成員和非靜態成員的區別?const 和 static readonly 區別?extern 是什麼意思?abstract 是什麼意思?internal 修飾符起什麼作用?sealed 修飾符是幹什麼的?override 和 overload 的區別?什麼是索引指示器?new 修飾符是起什麼作用?...