1. 程式人生 > >淺析C#中的結構體和類 筆記

淺析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 繼承。

結構可實現介面。其方式同類全然一樣。