天天看點

.Net 類型之辯

類型不是類。大多數程式員都知道類是啥,卻根本不知道類型是啥。

很多情況下,簡單的概念往往是最難搞清楚的。比如說,什麼是價格?什麼是企業?1991年諾貝爾經濟學獎得主科斯兩大貢獻之一就是回答“什麼是企業”(《企業的本質》)。

====

按照Benjamin C. Pierce 的觀點:

A type system is a syntactic method for enforcing levels of abstraction in programs.

每一種語言都有它自己的類型系統,下面是維基百科中對類型系統的定義:

在計算機科學中,類型系統用于定義如何将程式設計語言中的數值和表逹式歸類為許多不同的類型,如何操作這些類型,這些類型如何互相作用。類型可以确認一個值或者一組值具有特定的意義和目的(雖然某些類型,如抽象類型和函數類型,在程式運作中,可能不表示為值)。類型系統在各種語言之間有非常大的不同,也許,最主要的差異存在于編譯時期的文法,以及運作時期的操作實作方式。
如果一個語言強制實行類型規則(即通常隻允許以不丢失資訊為前提的自動類型轉換)就稱此處理為強類型,反之稱為弱類型。

上面俺還看得懂,下面這段話,俺就傻眼了:

類型可分為幾個大類: 原始類型      這是最簡單的類型種類,例如:整數和浮點數  整數類型      全部是數字的類型,例如:整數和自然數  浮點數類型      以浮點數表示數字的類型  複合類型      由基本類型組合成的類型,例如:數組或記錄單元。抽象資料類型具有複合類型和界面兩種屬性,這取決于你提及哪一個。  子類型      派生類型  對象類型      例如:變量類型  不完全類型(哥傻眼了)      遞歸類型  函數類型      例如:雙參函數  全稱量化類型(哥不知所雲)      如參數化類型、類型變量  存在量化類型(哥看着天花闆)      如子產品  精煉類型(哥看着窗外)      識别其它類型的子集的類型  依存類型(哥去WC)      取決于運作時期的數值的類型  所有權類型(哥去找小月月)      描述或限制面向對象系統結構的類型

我們不是搞程式語言的,不要求看懂上面這段話。直覺上來說:

(1)類型(type)不是類(class),類型和類是八竿子打不着的關系。别覺得類型帶個類字,就覺得他們是親戚,說出interface因為無法直接new就不是類型這種笑話;

(2)類型是一種邏輯概念,它代表一種抽象和限制關系。通過抽象關系來描述程式,通過限制關系來保證程式的健壯性。

.Net的類型系統叫公共類型系統(Common Type System,CTS)。公共類型系統是一種簡單的類型系統,像上面類型分類中那些複雜的類型在.Net中就很難找到對應物(也許F#能,哥低頭看地闆,反正那些類型指啥俺都不知道),玩類型的人都跑去玩haskell了。在他們看來,.Net的類型系統 too simple, too naive。

下圖是MSDN描述的公共類型系統的類型體系結構:

<a href="http://images.cnblogs.com/cnblogs_com/xiaotie/WindowsLiveWriter/a13d8d2bb141.Net_1144/image_2.png"></a>

我翻譯一下:

<a href="http://images.cnblogs.com/cnblogs_com/xiaotie/WindowsLiveWriter/a13d8d2bb141.Net_1144/image_4.png"></a>

值類型和引用類型是.Net的最基本的兩類類型。下面是MSDN上對值類型和引用類型的解釋:

Value types directly contain their data, and instances of value types are either allocated on the stack or allocated inline in a structure. Value types can be built-in (implemented by the runtime), user-defined, or enumerations. For a list of built-in value types, see the .NET Framework Class Library. Reference types store a reference to the value's memory address, and are allocated on the heap. Reference types can be self-describing types, pointer types, or interface types. The type of a reference type can be determined from values of self-describing types. Self-describing types are further split into arrays and class types. The class types are user-defined classes, boxed value types, and delegates.

從這上面可以看出,值類型和引用類型代表着兩類限制:

(1)值類型包含自己的資料,值類型配置設定在棧上或者内聯于其它結構體(structure,非struct!)之中;

(2)引用類型存儲的是到堆上資料的一個引用(這句話不完全準确,指針也可以指向棧上的資料)。

這樣一來,區分值類型和引用類型就很直接了。

type t = tValue,這裡的t如果包含它的資料,則type為值類型,如果t隻包含引用,具體取值還要根據記憶體去查找的話,則就是引用類型。

類型不一定非要有自己的資料。比如接口類型,它所指向的資料就是類類型的資料或者值類型裝箱為類類型後的資料。指針類型,它所指向的資料是值類型的資料。

下面是争論比較大的。

(1)指針類型。

int* p = xxx。根據上面的判斷方式,int*是引用類型。

(2)接口類型

IInterface i = (IInterface)Entity。這裡的i也隻是一個引用,如果Entity是class,則指向該class在堆上的位址,如果Entity是struct,則指向該struct裝箱之後,在堆上的位址。

(3)class和.class之辯

.Net中,萬物都是.class,這是實作層面,而關鍵字class則是類型層面的,它代表“類類型”。

有人說這是語言遊戲,其實不然。類型代表着限制,你隻有清楚這些限制,才能在.Net的規則下得心應手。下面深入談談:

(1)托管堆中的值類型

這裡需要反駁一個流傳甚廣的謬論:.Net中值類型在棧上,引用類型在托管堆上。

如:

int[] data = new int[100000000];

上例中數組是引用類型,數組裡的1億個int是值類型,你說這1億個值類型是在哪裡?肯定是在托管堆上,棧裡也塞不下啊。是以,我的看法是:

“作為引用類型資料成員的值類型是内聯在托管堆上引用類型資料内部的。”

别小看這種說法,下面看兩段代碼:

// a  int[] data0 = new int[100000000];  for (int i = 0; i &lt; data0.Length; i++)  {      data0[i] = i;  } // b  int[] data1 = new int[100000000];  int length = data1.Length;  for (int i = 0; i &lt; length; i++) 

(2)值類型的記憶體管理

.Net中值類型是很值得探讨的,它是編寫高性能.Net程式所必需了解的,也是使用純.Net代碼繞開GC,精細控制記憶體的唯一方式。

.Net的記憶體大體上有三塊:棧:由編譯器自動管理;托管堆:由GC管理;非托管堆:手動管理,手動配置設定和釋放。隻有值類型的資料是可以配置設定在棧上,可以配置設定在非托管堆上,也可以配置設定在非托管堆上的,而引用類型的資料(如果有的話),一定是托管堆上的。

值類型和指針類型是完全繞開GC的。這就為我們打開了兩扇門:

(a)實時程式設計。GC是實時程式設計的最大障礙。大量的使用值類型可以繞開GC,進行實時程式設計。要知道,對于Java那樣的語言,進行實時程式設計是非常困難的,甚至需要設計專門的實時Java虛拟機,.Net則完全不需要。這一點對有實時要求的控制系統非常重要。

(b)高性能程式設計。使用值類型和指針可以非常精細的操作記憶體,編寫高效的代碼:

· 你可以直接用指針去操作值類型; · 你可以将值類型内聯在class中,委托類類型用GC去管理值類型的生命周期; · 你可以将值類型配置設定在非托管堆中,自己管理它的生命周期; · 你可以将值類型配置設定在棧中,或者用stackalloc在棧中配置設定值類型數組。

(3)如果對.Net的類型系統不了解,可能會導緻程式開發中的問題。

比如,我以前不知道将值類型轉換為接口類型會進行裝箱操作,在圖像處理庫中正準備為每一個像素規定幾個接口進行抽象。一張圖檔有幾百萬像素幾千萬像素是很正常的,如果通過接口來操作這些像素會發生大量的裝箱操作,導緻程式性能急劇下降。

本文轉自xiaotie部落格園部落格,原文連結http://www.cnblogs.com/xiaotie/archive/2010/12/07/1898495.html如需轉載請自行聯系原作者

xiaotie 集異璧實驗室(GEBLAB)