.net中裝箱的幾種情況
本篇所寫都是本人想當然的理解。如果這種理解便于幫助你理解一些知識的話,我會感到由衷的欣慰。
.net中雖然沒有指針語法,但是在堆中分配對象,將引用放在棧中,十分類似C++中的指針操作,此時引用就可以看成一種特殊的指針。因為指針操作的間接性,會帶來一定的性能影響,為了避免這種影響,.net采取了一種折衷的辦法,引入了值類型。
為了在值類型和引用類型之間進行一些合理的轉換,于是帶來了裝箱和拆箱。
裝箱簡單來說就是將值類型轉換為引用類型。按三步進行:
(1)新分配托管堆內存(大小為值類型實例大小加上一個方法表指針和一個SyncBlockIndex)。
(2)將值類型的實例字段拷貝到新分配的內存中。
(3)返回托管堆中新分配對象的地址。
拆箱就是將引用類型轉換為對應的值類型。分如下步驟進行:
(1)檢查引用對象實例,確保它是給定值類型的一個裝箱值。
(2)獲取引用對象中指向值類型部分的指針。
(3)將引用對象中對應的內容拷貝到值類型區域。
從上面步驟可以看出,裝箱和拆箱會給程序的性能帶來一定的影響,所以我們應盡可能地避免裝箱和拆箱。裝箱可以隱式進行,拆箱只能顯式進行。只有先裝箱,才能拆箱。
為了盡可能地避免裝箱和拆箱,我們需要了解裝箱的幾種情況。
我總結了以下幾種(可能不太全面):
(1)方法中參數為Object類,但是傳遞一個值類型。

2



3


4

5

6

7



8

9

(2)一個類型中有field申明為Object類,賦予一個值類型。

2



3

4

5

6



7



8



9

10


11

12

13

14

15



16

17



18

19

20

21

22

(3)調用Object類中沒有被值類型覆蓋的方法,如GetType()。

2

3

4



5

6

7

8

9



10

11

12

13

14

15

16

17

18

19



20

21

22

23

24

25

26

(4)將值類型轉換為成一個被該值類型實現的接口類型。

2



3

4

5

6

7



8

9

10

11



12



13



14

15

16

17



18

19

20

21

22

23



24

25



26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

針對以上四種情況,為了減少裝箱和拆箱,建議以如下形式進行:
(1)方法中參數為Object類,但是傳遞一個值類型。 建議利用方法重載或者泛型。
(2)一個類型中有field申明為Object類,賦予一個值類型。 建議利用泛型。
(3)調用Object類中沒有被值類型覆蓋的方法,如GetType()。
根據實際情況,判斷是否有其它方法實現,如上面舉的例子就可以這樣修改:

2

3



4

5

6

7

8



9

10

11

12

13

14

15

16

17



18

19

20

21

22

23

24

(4)將值類型轉換為成一個被該值類型實現的接口類型。如果設計上真要求這么做,那可能只能如此了。我暫時沒有想到什么解法,如果你有更好的解法,希望不吝賜教。
posted on 2009-04-27 23:24 五味雜陳 閱讀(1743) 評論(1) 編輯 收藏 引用 所屬分類: .NET