先描述問題。
最近項目有個需求,數(shù)據(jù)入庫失敗后延時一定時間然后重新入庫;當(dāng)失敗達到一定次數(shù)后就不再進行入庫,因為項目簡單,也不需要異步處理。所以看到這個問題很容易想到用遞歸去實現(xiàn)。
我最開始的代碼example:
/// <summary> /// 錯誤次數(shù) /// </summary> static int errorCount = 0; /// <summary> /// 測試遞歸代碼 /// </summary> /// <returns></returns> static int TestFun() { try { Console.WriteLine("enter fun "); int a = 0; int n = 3 / a; } catch (Exception ex) { if (errorCount >= 3) { Console.WriteLine("number of error==3 bye"); return 0; } errorCount++; Thread.Sleep(1000); TestFun(); } return 1; }
這個代碼我想很多人第一眼看到就很容易想到這個TestFun方法一定返回0,因為除數(shù)不能為0 所以一直報錯 直到錯誤大于3 return了。
實際結(jié)果應(yīng)該是1 原因很簡單,catch里的return 是遞歸這個方法中的return。這個時候TestFun并沒有全部退出,只是退出了遞歸的那一層而已。遞歸退出完了 也就是catch語句塊執(zhí)行完畢后,會繼續(xù)執(zhí)行return1。
這個問題本身并不難理解,只是我們都有個固有的思維 方法中return了 就不會執(zhí)行下面代碼了。然后就會忽略下面的遞歸調(diào)用。
說到固有思維我再舉個例子還是這個問題。
/// <summary> /// 測試遞歸代碼 /// </summary> /// <returns></returns> static int TestFun() { int result = 1; try { Console.WriteLine("enter fun "); int a = 0; int n = 3 / a; } catch (Exception ex) { if (errorCount >= 3) { Console.WriteLine("number of error==3 bye"); result = 0; return 0; } errorCount++; Thread.Sleep(1000); TestFun(); } return result; }
這個代碼 不直接return具體值了,而是將值保存到一個變量里。第一眼看這個代碼心想這次應(yīng)該要返回0了吧,出錯后 result已經(jīng)被賦值0了 這下最后面的return 應(yīng)該返回1了。
正確結(jié)果其實也是返回1。說到底還是因為遞歸,我們catch 里的result=0 其實是針對當(dāng)前遞歸這個方法里面的result。因為我們先遞歸后改變值的;
我們可以這樣去想象:當(dāng)我一次遞歸時我們方法是TestFun1 第二次是TestFun2 第三次是 TestFun3 里面的代碼還是一樣的。所以我catch里面的result其實是對應(yīng)我TestFun3 里的result。直到我們退出遞歸回到最初的方法里面即TestFun 時它的result還是1并沒有改變。
造成我們直覺上的錯誤其實就是我一開始說的那種固有思維,代碼中變量被賦值后,下面代碼沒有再操作這個值 那么這個值應(yīng)該是被修改后的值;當(dāng)然這種思維在沒有遞歸代碼當(dāng)中肯定是正確的。
當(dāng)我們遞歸寫的少的情況很容易造成以上那種直覺上的錯誤判斷。
http://www.cnblogs.com/rui1236/p/7091721.html