1. 程式人生 > >c#類與結構體區別

c#類與結構體區別

終於寫到這裡了!下面就是我們大家期待已久的內容了!結構體與類的區別;希望通過我下面的講解,對大家能夠有所幫助,同時文章中有不足之處,大家多多指出哦!感激不盡!!!
這篇主要以程式碼和簡單文字說明來闡述它們的異同之處。

1.關鍵字不同
定義類使用關鍵字class ;定義結構使用關鍵字struct。相信這個大家都知道吧!

   //關鍵字struct
  struct Mystruct
    {

   //結構內容
    }

   //關鍵字class
    class MyClass
    {
    //類內容
    }

2.在語法上其實類和結構有著很多相似的地方.但是又有不同之處。

 struct Mystruct
    {
        private string name = "菜鳥";
        private int age = 26;
        public void MyMethod()
        {
            Console.WriteLine("Name:{0};Age:{1} ", this.name, this.age);

        }

    }

    class Program
    {

        private   string name="菜鳥"; 
        private
int age=26; public void MyMethod() { Console.WriteLine("Name:{0};Age:{1} ",this.name ,this .age); } static void Main(string[] args) { } }

這程式碼雖然看不出來錯誤;但是大家看下面的圖片;這裡寫圖片描述
很明顯結構體中編譯不通過啦!這是為什麼呢?請看錯誤型別:
發生錯誤
很明顯:這是結構體中與類的一個區別啦!
也就是說:在結構中欄位初始化語句是不允許的。會出現編譯錯誤。而類中是可以的哦!但是注意啦!類中這樣的寫法也是錯誤的啦!

 public string name; 
        name="菜鳥";

3.關於建構函式.
首先,關於隱式建構函式.我們知道,在類中如果我們沒有為類寫任意的建構函式,那麼C#編譯器在編譯的時候會自動的為這個類生成一個無引數的建構函式.我們將這個建構函式稱之為隱式建構函式 但是一旦我們為這個類寫了任意的一個建構函式的時候,這個隱式的建構函式就不會自動生成了.編譯器就會使用我們自己的構造函數了。而且類中的建構函式顯示宣告是可以是無引數的或者是帶有多個引數的過載的都可以。
但是在結構中,就不是這樣了,在結構中隱式的建構函式無論如何都存在。並且不允許我們顯示宣告無引數的建構函式,必須帶有引數。
首先是宣告一個無引數的建構函式:

    struct Mystruct
    {
        private string name;
        private int age;
        public Mystruct()
        {


        }
        public void MyMethod()
        {
            Console.WriteLine("Name:{0};Age:{1} ", this.name, this.age);

        }

    }

    class Program
    {

        public string name = "菜鳥";
        private int age = 26;
        public Program()
        {

        }

        public void MyMethod()
        {
            Console.WriteLine("Name:{0};Age:{1} ",this.name ,this .age);

        }


        static void Main(string[] args)
        {

        }
    }

這裡寫圖片描述
我們可以清晰的看到在結構體中宣告無引數的建構函式會出錯。而類中不會。這也是它們二者的區別。我們接著往下看:

 struct Mystruct
    {
        private string name;
        private int age;
        public Mystruct(string name,int age)
        {


        }
        public void MyMethod()
        {
            Console.WriteLine("Name:{0};Age:{1} ", this.name, this.age);

        }

    }

這裡寫圖片描述
可以看出,如果我們雖然聲明瞭不是無引數的建構函式,但是沒有完全對欄位賦值,編譯器同樣也是不通過的,而類則無次限制哦!
下面這樣寫就是對的啦

 struct Mystruct
    {
        private string name;
        private int age;
        public Mystruct(string name,int age)
        {
            this.name = name;
            this.age = age;

        }
        public void MyMethod()
        {
            Console.WriteLine("Name:{0};Age:{1} ", this.name, this.age);

        }

    }

下面我們看看類中是否可以宣告多個建構函式呢?

class Program
    {

        public string name = "菜鳥";
        private int age = 26;
        public Program()
        {

        }
        public Program(int age)
        {

        }
        public Program(int age, string name)
        {

        }
        public void MyMethod()
        {
            Console.WriteLine("Name:{0};Age:{1} ",this.name ,this .age);

        }
    }

答案當然是可以的啦!這就是方法過載嘛!!!
在結構中:隱式的無引數的建構函式在結構中無論如何都是存在的,所以程式設計師不能手動的為結構新增一個無引數的建構函式.而類中手動新增後就會覆蓋掉以前的無引數的建構函式哦!你們明白了沒?
在結構體的建構函式中,必須要為結構體的所有欄位賦值。

4.關於建立物件的方式:
我們知道類中建立物件都是通過new關鍵字來例項化出物件的。很簡單的啦!

 static void Main(string[] args)
        {
           //建立類的物件p;
            Program p = new Program();
        }

而建立結構體物件可以不使用new關鍵字.直接宣告一個變數就可以.但是這樣的話,結構體物件中的欄位是沒有初始值的,所以在使用欄位之前必須要為這個欄位賦值.

  static void Main(string[] args)
        {
            Program p = new Program();
            Mystruct my;
            Console.WriteLine(my.name );//編譯錯誤

        }

這裡寫圖片描述
如果我們的欄位在結構中沒有賦值的話,會出現編譯錯誤。
原因很簡單.因為宣告的時候就不能給初始值,雖然建構函式中為物件的欄位賦值,但是此種方式建立結構體物件,沒有呼叫建構函式,所以必須要程式設計師在使用之前手動賦值。下面這樣就可以啦!

 static void Main(string[] args)
        {
            Program p = new Program();
            Mystruct my;
            my.name = "菜鳥";
            Console.WriteLine(my.name );

        }

當然了,你也可以像建立類的物件一樣來為結構體賦值啦!
使用new關鍵字來建立,與不使用new關鍵字建立不同的是,通過使用new關鍵字建立結構體物件後,這個結構體物件的欄位就已經有值了.原因是new關鍵字呼叫了建構函式,而結構體建構函式要求必須要為所有的欄位賦值.

static void Main(string[] args)
        {
            Program p = new Program();
            Mystruct my = new Mystruct();
            Console.WriteLine(my.name );


        }

雖然我這裡面並沒有給我的建構函式賦值,但是系統會預設呼叫建構函式,並賦值為null的。這裡是建立物件的不同啦!!!

5.繼承時候的不同:
結構體不能從另外一個結構或者類繼承,但是可以實現介面.

struct Mystruct:Program 
    {
        public  string name;
        private int age;
        public Mystruct(string name,int age)
        {
            this.name = name;
            this.age = age;

        }
        public void MyMethod()
        {
            Console.WriteLine("Name:{0};Age:{1} ", this.name, this.age);

        }

    }

這裡寫圖片描述
我們發現這樣我們的結構體不能繼承類;會出現編譯錯誤。而且錯誤型別為介面,所以我們的結構體可以進行介面繼承啦!

6.本質區別:結構體是值型別 ,類是引用型別。
結構體是值型別,當其作為一個區域性變數的時候,變數是儲存在棧空間中的,其物件的欄位直接儲存在這個變數中的.與引用型別的類不一樣,引用型別的變數中儲存的是物件在堆空間中的地址,所以當我們傳遞一個引用型別的變數的時候,其實傳遞的是變數的值(物件的地址)即指向物件的引用(可以叫棧指標(但是微軟對於c#方面一直弱化指標概念,個人認為知道指標會方便理解的,有興趣的可以學學c++)) 傳遞完以後 對變數的修改會影響到另外一個變數指向的物件的值.
7.結構體無解構函式,而類有解構函式。
原因呢?還是很簡單啊!因為類是引用型別,儲存在堆上面,解構函式在釋放記憶體時呼叫的,由我們的GC垃圾回收器去呼叫它的。是儲存在堆上面的,而我們的結構體是值型別啊!所以壓根不會由解構函式啊!要它幹什麼呢?嘿嘿!這樣是不是可以更好的去理解呢???
8.最後說說什麼時候使用它們吧!
結構儲存在棧中,而棧有一個特點,就是空間較小,但是訪問速度較快,堆空間較大,但是訪問速度相對較慢.所以當我們描述一個輕量級物件的時候,可以將其定義為結構來提高效率當描述一個重量級物件的時候,我們知道類的物件是儲存在堆空間中的,我們就將重量級物件定義為類. 他們都表示可以包含資料成員和函式成員的資料結構。與類不同的是,結構是值型別並且不需要堆分配。結構型別的變數直接包含結構的資料,而類型別的變數包含對資料的引用(該變數稱為物件)。
希望這三篇部落格能夠對你們有點幫助啦!
文章寫的比較倉促,不足之處,請多多指教啦!歡迎評論交流!