淺析C#中的結構體和類 筆記
類和結構是 .NET Framework 中的常規型別系統的兩種基本構造。 兩者在本質上都屬於資料結構。封裝著一組總體作為一個邏輯單位的資料和行為。 資料和行為是該類或結構的“成員”,它們包括各自的方法、屬性和事件等
對於C/C++程式設計師來說。結構體和類的差別非常小。僅僅是結構體的預設成員變數為public,類的預設成員變數為private。
C# 結構的特點
您已經用了一個簡單的名為 Books 的結構。在 C# 中的結構與傳統的 C 或 C++ 中的結構不同。C# 中的結構有以下特點:
- 結構可帶有方法、欄位、索引、屬性、運算子方法和事件。
- 結構可定義建構函式,但不能定義解構函式。但是,您不能為結構定義預設的建構函式。預設的建構函式是自動定義的,且不能被改變。
- 與類不同,結構不能繼承其他的結構或類。
- 結構不能作為其他結構或類的基礎結構。
- 結構可實現一個或多個介面。
- 結構成員不能指定為 abstract、virtual 或 protected。
- 當您使用 New 操作符建立一個結構物件時,會呼叫適當的建構函式來建立結構。與類不同,結構可以不使用 New 操作符即可被例項化。
- 如果不使用 New 操作符,只有在所有的欄位都被初始化之後,欄位才被賦值,物件才被使用。
可是對於C#來說,結構體和類有非常多的不同。
首先來談一談為何須要結構體:
最主要的原因就是結構體有能力去管理、使用不同資料型別的組合。
.NET支援值型別和引用型別的概念,全部的C#內建型別中,除了string外均為值型別。
在C#中,結構體是值型別。類是引用型別。
值型別能夠降低對堆的管理、使用。降低垃圾回收,表現出更好的效能。可是值型別也有不好的一面。比方會涉及到裝箱拆箱等操作。
以下定義一個結構體:
public struct Foo { // Fields private string fooString; private int fooNumber; // Property public string FooString { get { return fooString; } set { fooString = value; } } // Method public int GetFooNumber() { return fooNumber; } }
能夠看到。結構體和類非常的類似。讓我們更深層次的看看兩者的不同。
1繼承
結構體繼承自System.ValueType,而類繼承自System.Object。結構體不能繼承其它的類或結構體,可是能夠把結構體當做是介面。因為介面僅僅是用於引用型別的操作,所以把結構體當成介面就會隱式的發生裝箱操作。
比如例如以下程式碼:
struct Foo : IFoo
{
int x;
}
IFoo iFoo = new Foo();
2構造
C#不同意結構體具有無引數的預設建構函式。原因是:對於值型別,編譯器既不會生成預設建構函式。也不會呼叫預設建構函式。所以你不能這樣初始化:
struct MyWrongFoo
{
int x = 1;
}
可是你能夠使用new:
Foo foo = new Foo();
這裡須要注意的是,雖然使用了new操作,可是結構體分配在棧上,而不是堆上。更有趣的是,new操作沒有呼叫無引數的建構函式。
看看以下的程式碼:
struct Foo
{
int x;
public Foo(int x)
{
this.x = x;
}
}
class FooTester
{
[STAThread]
static void Main(string[] args)
{
Foo f = new Foo();
}
}
這裡我過載了建構函式。就能夠使用new了。
所以我們能夠這樣:
呼叫 new Foo()
呼叫過載的建構函式初始化
顯示的設定每一個值:
Foo foo;
foo.x = 0;
3析構
我們不能為結構體定義解構函式。
4僅僅讀關鍵字
對於引用型別。readonly關鍵字阻止你將引用指到其它物件,可是無法阻止你改變該物件的狀體。
對於值型別來說。readonly關鍵字與C++中的const非常像。阻止你改變物件的狀態。
class MyReferenceType
{
int state;
public int State
{
get
{
return state;
}
set
{
state = value;
}
}
}
struct MyValueType
{
int state;
public int State
{
get
{
return state;
}
set
{
state = value;
}
}
}
class Program
{
readonly MyReferenceType myReferenceType = new MyReferenceType();
readonly MyValueType myValueType = new MyValueType();
public void SomeMethod()
{
myReferenceType = new MyReferenceType(); // Compiler Error
myReferenceType.State = 1234; // Ok
myValueType = new MyValueType(); // Compiler Error
myValueType.State = 1234; // Compiler Error
}
}
總結:
為結構定義預設(無引數)建構函式是錯誤的。
在結構體中初始化例項欄位也是錯誤的。
僅僅能通過兩種方式初始化結構成員:一是使用引數化建構函式,二是在宣告結構後分別訪問成員。 對於不論什麼私有成員或以其它方式設定為不可訪問的成員,僅僅能在建構函式中進行初始化。
假設使用 new 運算子建立結構物件。則會建立該結構物件。並呼叫適當的建構函式。
與類不同,結構的例項化能夠不使用 new 運算子。
在此情況下不存在建構函式呼叫。因而能夠提高分配效率。 可是,在初始化全部欄位之前,欄位將保持未賦值狀態且物件不可用。
當結構包括引用型別作為成員時,必須顯式呼叫該成員的預設建構函式,否則該成員將保持未賦值狀態且該結構不可用。 (這將導致編譯器錯誤 CS0171。)
對於結構。不像類那樣存在繼承。 一個結構不能從還有一個結構或類繼承。並且不能作為一個類的基。 可是,結構從基類 Object 繼承。
結構可實現介面。其方式同類全然一樣。