日韩天天综合网_野战两个奶头被亲到高潮_亚洲日韩欧美精品综合_av女人天堂污污污_视频一区**字幕无弹窗_国产亚洲欧美小视频_国内性爱精品在线免费视频_国产一级电影在线播放_日韩欧美内地福利_亚洲一二三不卡片区

裝箱、轉型、方法調(diào)用他們究竟有什么區(qū)別?_.Net教程

編輯Tag賺U幣
教程Tag:暫無Tag,歡迎添加,賺取U幣!

推薦:使用Ajax后,原來導出功能失敗的解決方法
問題描述:我們的產(chǎn)品在Ajax后(使用微軟的UpdatePanel),其中的導出功能出現(xiàn)錯誤。因為導出功能使用了Response直接輸出內(nèi)容,而Ajax的異步方式對此不能解析導致出現(xiàn)錯誤。 解決過程:在網(wǎng)上

以下為引用的內(nèi)容:
裝箱、轉型、方法調(diào)用這些我們天天進行的日常工作之前到底有什么差別?

以下為引用的內(nèi)容:
struct UserInfoStruct
2{
3 public int UserId;
4 public string UserName;
5}
6class UserInfoClass
7{
8 private int UserId;
9 private string UserName;
10}
11class Program
12{
13
14 static void Main(string[] args)
15 {
16 object objString = "abc";
17
18 string aString = (string)objString;
19 string bString = objString.ToString();
20 string cString = Convert.ToString(objString);
21
22 object objInt = 5;
23 int aInt = (int)objInt;
24 int bInt = Convert.ToInt32(objInt);
25
26 object objStruct = new UserInfoStruct();
27 UserInfoStruct aUserInfoStruct = (UserInfoStruct)objStruct;
28
29 object objClass = new UserInfoClass();
30 UserInfoClass aUserInfoClass = (UserInfoClass)objClass;
31 }
32}

前幾天在群里聊天,有人問:

string aString = (string)objString;

string bString = objString.ToString();有什么區(qū)別,我當時就回答“一個是轉型、一個是方法調(diào)用”,剛說完就覺得自己是在說廢話,其實我也不知道內(nèi)部到底發(fā)生了什么,如是就reflector,ILDASM,google一起上,現(xiàn)在把弄出來的結果整理了一下,share出來,并把相似的幾個都集在一起討論,由于我不懂WinDbg,所以無法深入,就淺嘗輒止吧。

下面是main方法的IL代碼:

以下為引用的內(nèi)容:
1.method private hidebysig static void Main(string[] args) cil managed
2{
3 .entrypoint
4 // Code size 97 (0x61)
5 .maxstack 1
6 .locals init ([0] object objString,
7 [1] string aString,
8 [2] string bString,
9 [3] string cString,
10 [4] object objInt,
11 [5] int32 aInt,
12 [6] int32 bInt,
13 [7] object objStruct,
14 [8] valuetype SomeKits.UserInfoStruct aUserInfoStruct,
15 [9] object objClass,
16 [10] class SomeKits.UserInfoClass aUserInfoClass,
17 [11] valuetype SomeKits.UserInfoStruct CS$0$0000)
18 IL_0000: nop
19 IL_0001: ldstr "abc"
20 IL_0006: stloc.0
21 IL_0007: ldloc.0
22 IL_0008: castclass [mscorlib]System.String
23 IL_000d: stloc.1
24 IL_000e: ldloc.0
25 IL_000f: callvirt instance string [mscorlib]System.Object::ToString()
26 IL_0014: stloc.2
27 IL_0015: ldloc.0
28 IL_0016: call string [mscorlib]System.Convert::ToString(object)
29 IL_001b: stloc.3
30 IL_001c: ldc.i4.5
31 IL_001d: box [mscorlib]System.Int32
32 IL_0022: stloc.s objInt
33 IL_0024: ldloc.s objInt
34 IL_0026: unbox.any [mscorlib]System.Int32
35 IL_002b: stloc.s aInt
36 IL_002d: ldloc.s objInt
37 IL_002f: call int32 [mscorlib]System.Convert::ToInt32(object)
38 IL_0034: stloc.s bInt
39 IL_0036: ldloca.s CS$0$0000
40 IL_0038: initobj SomeKits.UserInfoStruct
41 IL_003e: ldloc.s CS$0$0000
42 IL_0040: box SomeKits.UserInfoStruct
43 IL_0045: stloc.s objStruct
44 IL_0047: ldloc.s objStruct
45 IL_0049: unbox.any SomeKits.UserInfoStruct
46 IL_004e: stloc.s aUserInfoStruct
47 IL_0050: newobj instance void SomeKits.UserInfoClass::.ctor()
48 IL_0055: stloc.s objClass
49 IL_0057: ldloc.s objClass
50 IL_0059: castclass SomeKits.UserInfoClass
51 IL_005e: stloc.s aUserInfoClass
52 IL_0060: ret
53}

將IL代碼和源代碼比較得知

string aString = (string)objString;的IL代碼是 castclass [mscorlib]System.String

這個過程發(fā)生了什么?首先在這個指令之前l(fā)dloc.0是將第一個局部變量的引用壓入堆棧中,然后從堆棧頂上彈出對象的引用,將這個引用轉型為這個指令指定的類型,如果轉型成功的話將轉型的結果壓入棧頂。那什么情況下轉型成功,什么情況下轉型將不成功呢?當這個棧頂?shù)膶ο蟛皇瞧谕念惖淖宇惖脑捘蔷娃D型失敗了,就會拋出InvalidCastException異常。那如果棧頂?shù)膶ο笫莕ull怎么辦?會觸發(fā)異常么?答案是不會,如果棧頂上的元素是null的時候,轉型結果也是null,不會引發(fā)什么異常。

對于string bString = objString.ToString()就沒有什么好說的了,從生成的代碼callvirt instance string [mscorlib]System.Object::ToString()來看,它調(diào)用了object的ToString()方法,使用的是callvirt指令,那實際上調(diào)用的是string類里面重寫object的那個ToString()。
string cString = Convert.ToString(objString)這種形式在內(nèi)部到底發(fā)生了什么呢?我們看看Convert類的ToString(object)靜態(tài)方法的實現(xiàn):

以下為引用的內(nèi)容:
public static string ToString(object value)
{
return ToString(value, null);
}

public static string ToString(object value, IFormatProvider provider)
{
IConvertible convertible = value as IConvertible;
if (convertible != null)
{
return convertible.ToString(provider);
}
IFormattable formattable = value as IFormattable;
if (formattable != null)
{
return formattable.ToString(null, provider);
}
if (value != null)
{
return value.ToString();
}
return string.Empty;
}

在Convert.ToString()方法里,首先將對象嘗試轉型為IConvertible接口,如果轉型成功就會調(diào)用這個接口的ToString()方法了,所以你想想,如果我們要讓我們自己寫的類型支持Convert.ToString()這種寫法怎么辦?那就實現(xiàn)IConvertible接口吧。

object objInt = 5這個又發(fā)生了什么?它對應的IL指令是:box [mscorlib]System.Int32,box是裝箱指令,具體分三步進行:

1.在托管堆上分配一塊內(nèi)存,內(nèi)存的大小是值類型的大小然后加上兩個所有引用類型都有的附加字段:SyncBlockIndex和一個放發(fā)表指針

2.將棧上的值類型拷貝到剛才申請的類型中

3.返回剛在托管堆上申請的對象引用,將其壓入棧

從這里看裝箱不僅僅耗費內(nèi)存還將東西拷貝來拷貝去的,真是賠了夫人又折兵啊。

int aInt = (int)objInt又干了些什么呢?還是類型轉換么?它對應的IL代碼是

unbox.any [mscorlib]System.Int32

這個稱之為拆箱,顧名思義就是將剛才的已裝箱類型給“轉換”為未裝箱時候的值類型,從這個層面看拆箱好像是裝箱的“逆過程”,實際上卻不是,拆箱是通過這樣的兩步進行的:

1.從棧上獲取托管堆中已裝箱對象的地址

2.從已裝箱對象中獲取剛才那個拷貝過去的值類型的地址

看到?jīng)],拆箱比起裝箱起來少了一步,這里并沒有將已裝箱類型中的值類型拷貝到棧上,看起來拆箱并沒有涉及到內(nèi)存的拷貝操作,它做的僅僅是做一下地址的提取,但是實際中拆箱后往往緊跟著的就是內(nèi)存的拷貝。從上面的代碼中我們可以看到裝箱和拆箱是很消耗資源的操作,所以我們需要特別注意,特別是一些隱式的,我們常常忽略了。

按照上一小節(jié)的結論,string cString = Convert.ToString(objString)能夠編譯通過是因為int類型實現(xiàn)了IConvertible接口,通過Reflector查看代碼果真如此。

上面是對.net基元類型的一些討論,那么對于自己寫的struct和class是怎樣的呢?

通過IL代碼,可知對于值類型的struct

object objStruct = new UserInfoStruct();

UserInfoStruct aUserInfoStruct = (UserInfoStruct)objStruct;

就是裝箱拆箱的過程

對于引用類型的class UserInfoClass aUserInfoClass = (UserInfoClass)objClass就是castclass指令的操作。
由于本人對WinDbg一無所知,所以也無法在更深一層次討論這些機制的最底層實現(xiàn),實屬遺憾,希望能有一些達人對底層做進一步解釋。

分享:ASP.NET蔚昜璃唗蹈趙傖Binary揣湔祫DB or File
郔輪衄?婓枒蹦涴跺恀枙..苤萊竭屾?zhèn)`涴跺陲昹..憩善厙繚奻梑賸珨虳訧埭..諒湮模?睡蔚昜璃唗蹈趙傖Binary Data..?綴揣湔善訧蹋踱麼紫黓孬.. 絞?褫眕唗蹈趙..憩珨隅褫眕毀唗蹈趙賸...?妗唗蹈趙跡宒

來源:模板無憂//所屬分類:.Net教程/更新時間:2008-08-22
相關.Net教程