国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

編寫高質(zhì)量代碼改善C#程序的157個(gè)建議——建議61:避免在finally內(nèi)撰寫無(wú)效代碼

2019-11-14 14:06:24
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

建議61:避免在finally內(nèi)撰寫無(wú)效代碼

在闡述建議之前,需要先提出一個(gè)問(wèn)題:是否存在一種打破try-finally執(zhí)行順序的情況,答案是:不存在(除非應(yīng)用程序本身因?yàn)槟承┖苌俪霈F(xiàn)的特殊情況在try塊中退出)。應(yīng)該始終認(rèn)為finally內(nèi)的代碼會(huì)在方法return之前執(zhí)行,哪怕return在try塊中。

正是這點(diǎn),可能會(huì)讓你寫出無(wú)效的代碼,有時(shí)候,這樣的無(wú)效代碼會(huì)是一個(gè)隱藏很深的Bug。

看下面代碼:

        PRivate static int TestIntReturnBelowFinally()        {            int i;            try            {                i = 1;            }            finally            {                i = 2;                Console.WriteLine("/t將int結(jié)果改為2,finally執(zhí)行完畢");            }            return i;        }

返回值是2。

但是:

        private static int TestIntReturnInTry()        {            int i;            try            {                return i = 1;            }            finally            {                i = 2;                Console.WriteLine("/t將int結(jié)果改為2,finally執(zhí)行完畢");            }        }

返回值是1。

再看下面代碼:

        static User TestUserReturnInTry()        {            User user = new User() { Name = "Mike", BirthDay = new DateTime(2010, 1, 1) };            try            {                return user;            }            finally            {                user.Name = "Rose";                user.BirthDay = new DateTime(2010, 2, 2);                Console.WriteLine("/t將user.Name改為Rose");            }        }

user類:

    class User    {        public string Name { get; set; }        public DateTime BirthDay { get; set; }    }
View Code

TestUserReturnInTry方法返回的User中,Name的值已經(jīng)改為Rose了。

 

現(xiàn)在來(lái)解釋為什么上面3個(gè)函數(shù)會(huì)有3種結(jié)果。查看TestIntReturnBelowFinally的finally部分的IL代碼:

  finally  {    IL_0004:  ldc.i4.2    IL_0005:  stloc.0    IL_0006:  ldstr      bytearray (09 00 06 5C 69 00 6E 00 74 00 D3 7E 9C 67 39 65   // .../i.n.t..~.g9e                                    3A 4E 32 00 0C FF 66 00 69 00 6E 00 61 00 6C 00   // :N2...f.i.n.a.l.                                    6C 00 79 00 67 62 4C 88 8C 5B D5 6B )             // l.y.gbL..[.k    IL_000b:  call       void [mscorlib]System.Console::WriteLine(string)    IL_0010:  endfinally  }  // end handler  IL_0011:  ldloc.0  IL_0012:  ret}

IL_0004: ldc.i4.2”首先將2壓入棧頂

IL_0005: stloc.0”將最頂層堆棧的值,也就是2賦值給本地變量,也就是 i (index 0)

IL_0011: ldloc.0”將本地變量 i (index 0)的值再次壓入棧

IL_0012: ret”結(jié)束函數(shù),同時(shí)把棧內(nèi)的返回值壓入調(diào)用者的棧中。就函數(shù)將2賦值給了返回值。

 

看方法TestIntReturnInTry()的Debug版本的IL代碼:

.method private hidebysig static int32  TestIntReturnInTry() cil managed{  // 代碼大小       27 (0x1b)  .maxstack  2  .locals init ([0] int32 i,           [1] int32 CS$1$0000)  IL_0000:  nop  .try  {    IL_0001:  nop    IL_0002:  ldc.i4.1    IL_0003:  dup    IL_0004:  stloc.0    IL_0005:  stloc.1    IL_0006:  leave.s    IL_0018  }  // end .try  finally  {    IL_0008:  nop    IL_0009:  ldc.i4.2    IL_000a:  stloc.0    IL_000b:  ldstr      bytearray (09 00 06 5C 69 00 6E 00 74 00 D3 7E 9C 67 39 65   // .../i.n.t..~.g9e                                    3A 4E 32 00 0C FF 66 00 69 00 6E 00 61 00 6C 00   // :N2...f.i.n.a.l.                                    6C 00 79 00 67 62 4C 88 8C 5B D5 6B )             // l.y.gbL..[.k    IL_0010:  call       void [mscorlib]System.Console::WriteLine(string)    IL_0015:  nop    IL_0016:  nop    IL_0017:  endfinally  }  // end handler  IL_0018:  nop  IL_0019:  ldloc.1  IL_001a:  ret} // end of method Program::TestIntReturnInTry

TestIntReturnInTry在IL中創(chuàng)建了兩個(gè)本地變量 i 和CS$1$0000 ,i 存儲(chǔ)的是1,然后finally中 i 被賦值為2。調(diào)用者真正得到的是由IL創(chuàng)建的CS$1$0000所對(duì)應(yīng)的值。用Reflector查看C#代碼:

private static int TestIntReturnInTry(){    int i;    int CS$1$0000;    try    {        CS$1$0000 = i = 1;    }    finally    {        i = 2;        Console.WriteLine("/t將int結(jié)果改為2,finally執(zhí)行完畢");    }    return CS$1$0000;}

實(shí)際上,finally中i=2沒(méi)有任何意義,所以在本函數(shù)的release版本中,IL中找不到對(duì)應(yīng)的代碼:

.method private hidebysig static int32  TestIntReturnInTry() cil managed{  // 代碼大小       17 (0x11)  .maxstack  1  .locals init ([0] int32 CS$1$0000)  .try  {    IL_0000:  ldc.i4.1    IL_0001:  stloc.0    IL_0002:  leave.s    IL_000f  }  // end .try  finally  {    IL_0004:  ldstr      bytearray (09 00 06 5C 69 00 6E 00 74 00 D3 7E 9C 67 39 65   // .../i.n.t..~.g9e                                    3A 4E 32 00 0C FF 66 00 69 00 6E 00 61 00 6C 00   // :N2...f.i.n.a.l.                                    6C 00 79 00 67 62 4C 88 8C 5B D5 6B )             // l.y.gbL..[.k    IL_0009:  call       void [mscorlib]System.Console::WriteLine(string)    IL_000e:  endfinally  }  // end handler  IL_000f:  ldloc.0  IL_0010:  ret} // end of method Program::TestIntReturnInTry

用Reflector查看release版本中C#代碼:

private static int TestIntReturnInTry(){    int CS$1$0000;    try    {        CS$1$0000 = 1;    }    finally    {        Console.WriteLine("/t將int結(jié)果改為2,finally執(zhí)行完畢");    }    return CS$1$0000;}

 

再解釋第三個(gè)方法TestUserReturnInTry為什么返回的是“Rose”。Reflector查看release版本中C#代碼:

private static User TestUserReturnInTry(){    User CS$1$0000;    User <>g__initLocal0 = new User {        Name = "Mike",        BirthDay = new DateTime(0x7da, 1, 1)    };    User user = <>g__initLocal0;    try    {        CS$1$0000 = user;    }    finally    {        user.Name = "Rose";        user.BirthDay = new DateTime(0x7da, 2, 2);        Console.WriteLine("/t將user.Name改為Rose");    }    return CS$1$0000;}

 

User是引用類型, CS$1$0000 = user;說(shuō)明CS$1$0000和user指向的是同一個(gè)對(duì)象,當(dāng)在finally中 user.Name = "Rose"時(shí)CS$1$0000的Name也會(huì)變?yōu)?ldquo;Rose”。所以返回的CS$1$0000的Name為“Rose”。

 

再舉一個(gè)例子:

 

        private static User TestUserReturnInTry2()        {            User user = new User() { Name = "Mike", BirthDay = new DateTime(2010, 1, 1) };            try            {                return user;            }            finally            {                user.Name = "Rose";                user.BirthDay = new DateTime(2010, 2, 2);                user = null;                Console.WriteLine("/t將user置為anull");            }        }

 

返回的結(jié)果不是null,而一個(gè)Name=“Rose”,BirthDay = new DateTime(2010, 2, 2)的User對(duì)象。Reflector查看release版本中C#代碼:

private static User TestUserReturnInTry2(){    User CS$1$0000;    User <>g__initLocal1 = new User {        Name = "Mike",        BirthDay = new DateTime(0x7da, 1, 1)    };    User user = <>g__initLocal1;    try    {        CS$1$0000 = user;    }    finally    {        user.Name = "Rose";        user.BirthDay = new DateTime(0x7da, 2, 2);        user = null;        Console.WriteLine("/t將user置為anull");    }    return CS$1$0000;}

 

CS$1$0000和user指向的是同一個(gè)對(duì)象當(dāng)在finally中 user=null 時(shí),只是user指向?yàn)閚ull了,CS$1$0000指向的對(duì)象并沒(méi)有變。

 

 

轉(zhuǎn)自:《編寫高質(zhì)量代碼改善C#程序的157個(gè)建議》陸敏技


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 普洱| 彭山县| 岐山县| 浦县| 景谷| 思茅市| 电白县| 承德县| 温宿县| 大宁县| 栖霞市| 疏附县| 乌兰浩特市| 桃园县| 宝丰县| 驻马店市| 卢氏县| 永修县| 乌拉特前旗| 道真| 合阳县| 北碚区| 丹江口市| 桓台县| 额敏县| 泾阳县| 山东| 池州市| 墨脱县| 黄浦区| 马山县| 故城县| 彰武县| 天长市| 保德县| 武清区| 紫阳县| 阳城县| 乐至县| 四平市| 保山市|