類和結構是 .NET Framework 中的常規類型系統的兩種基本構造。 兩者在本質上都屬於數據結構。封裝着一組總體作為一個邏輯單位的數據和行為。 數據和行為是該類或結構的“成員”,它們包括各自的方法、屬性和事件等
對於C/C++程序員來說。結構體和類的差別非常小。僅僅是結構體的默認成員變量為public,類的默認成員變量為private。
可是對於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 繼承。
結構可實現接口。其方式同類全然一樣。
