C# struct

簡介

C/C++程序員或多或少都有使用struct的經歷,在C++structclass的區別不大,除了默認成員的可訪問性,這點在C#中則大相徑庭。本文將力圖說明C#structclass的區別以及如何正確的使用structjava

爲何須要struct?

衆所周知,在java中並無struct的概念,那麼C#爲什麼引入struct呢?最基本緣由是能夠建立值類型的類型,使在託管環境中有更好的性能。程序員

區別於javaC#有值類型和引用類型的概念(java只有引用類型)。引用類型的實例分配在堆上,當對象沒有被引用時被垃圾回收器回收;值類型的實例分配在棧上,當離開其做用域後內存被回收。值類型自己存儲的是值自己,引用類型存儲的是引用,C#語言提供的原始類型除了string類型其它都是值類型。函數

C#struct是值類型,class是引用類型,能夠經過enumstruct關鍵字建立值類型的對象。使用值類型能夠減小託管堆上對象的數量,從而減小垃圾回收器(GC)的負擔,提升性能,值類型也有明顯的缺點:經過值類型傳遞較大對象的開銷比較昂貴、裝箱和拆箱對性能形成影響。性能

Classes 和Structs

 

 public struct Employeestruct
    {
        private int _fooNumber;

        public Employeestruct(int fooNumber)
            : this()
        {
            _fooNumber = fooNumber;
        }

        public string Name { get; set; }

        public int Age { get; set; }

        public string GetMessage()
        {
            return string.Format("{0}--{1}", Name, Age);
        }
    }

 

從上面能夠看到,structclass很是類似,不過它們仍是有本質的區別,接下來咱們就一一分析。this

1. Structs 和Inheritance

StructsSystem.ValueType繼承而classes繼承於System.Object或從System.Object繼承的其餘類型,固然System.ValueType也從System.Object繼承(這不是重點)Structs能夠實現接口,但不能從另外一個classesstructs繼承,並且不能做爲其餘classes的基類。要知道,當你把structs做爲接口使用時,就進行一次隱形裝箱,由於接口做爲引用類型。請看下面代碼:spa

struct Foo : IFoo
{ 
      int x;
}

IFoo iFoo = new Foo();

 

Foo的實例被建立並賦值給iFoo(裝箱),當iFoo調用時實際上使用的是Foo裝箱後的實例。.net

2. Constructors

儘管CLR容許,可是不容許在structs中定義無參的構造函數。對於值類型,編譯器默認狀況下不生成默認的構造函數,也不調用默認的構造函數,因此C#編譯器不容許使用者定義無參的構造函數。因爲structs不生成默認的構造函數,因此不能初始化字段。以下(錯誤):code

Struct MyFoo
{
        int x = 1;
}

 

記住,編譯器把初始化工做放在構造函數中,因爲structs沒有默認的構造函數,因此不能初始化字段。orm

有趣的是,你可使用下面的語法:對象

Foo foo  =  new Foo();

經過以前的章節瞭解到,儘管初始化foo使用了new操做符,可是structs的實例分配到棧上。new Foo()不會調用無參的構造函數,僅僅是初始化該struct的字段爲默認值。

 

struct Foo
{
       int x;

       public Foo(int x)
       {
           this.x = x;
       }
}    

Foo foo  =  new Foo();

 

注意,我已經重載了構造函數,然而我可以調用new Foo()

3. Destructors

Structs不容許定義析構函數,若是你扔就去定義一個析構函數,編譯器會當即提示一個錯誤,不過structs能夠實現IDisposable接口。

4. Comparison against null

Structs不能和null進行比較,這點在.net framework2.0已再也不是問題(可空類型),關於可空類型,超出本文討論範圍。

5. Readonly關鍵字

對於引用類型,readonly阻止再爲變量賦值,但不阻止你修改當前引用對象的狀態。對於值類型,readonly有點相似C++中的const關鍵字,它阻止你修改引用對象,也意味着不能再爲他賦值,由於這會致使從新初始化一次。請看下面代碼:

    public class MyReferenceType
    {
        public int State { get; set; }
    }

    public struct MyValueType
    {
        public int State { get; set; }
    }

   public void TestMethod()
    {
        myReferenceType = new MyReferenceType(); // 錯誤
        myReferenceType.State = 1234; // Ok

        myValueType = new MyValueType(); // 錯誤
        myValueType.State = 1234; //  錯誤
    }

 

foreach 語句和using語句的變量爲隱式readonly,因此若是使用structs,將沒法更改其狀態。

什麼時候使用 structs

經過前面的描述已經清楚classesstructs的區別,那咱們來看下適合使用structs的場景:

l 實例使用起來像C#的基元類型

l 須要建立大量的、短暫實例(例如在循環體內)

l 實例不須要大量的傳遞

l 不須要從其餘類型繼承或不但願被其餘類型繼承

l 但願被人操做你實例的副本

不適合使用structs的場景:

l 實例過大,當實例過大時,傳遞實例會有很大的開銷。微軟建議structs的理想大小應該在16bytes如下

l 當回引發裝箱、拆箱操做時。關於裝箱、拆箱超出本文討論範圍

相關文章
相關標籤/搜索