解析C#中止言與異常的運用方法及異常處置的流程掌握。本站提示廣大學習愛好者:(解析C#中止言與異常的運用方法及異常處置的流程掌握)文章只能為提供參考,不一定能成為您想要的結果。以下是解析C#中止言與異常的運用方法及異常處置的流程掌握正文
斷言與異常(Assertion Vs Exception)
在平常編程理論中,斷言與異常的界線不是很顯著,這也使得它們經常沒有被准確的應用。我也在赓續的與這個隱約的怪獸格斗,僅寫此文和年夜家分享一下我的小我意見。我想我們還可以從許多角度來差別斷言和異常的應用場景,迎接年夜家的看法和建議。
異常的應用場景:用於捕捉內部的能夠毛病
斷言的應用場景:用於捕捉外部的弗成能毛病
我們可以先細心剖析一下我們在.net中曾經存在的異常。
起首,我們先不將它們算作異常,由於我們如今還沒有在異常和斷言之間劃清界線,我們先將它們算作毛病。
當我們在編碼的第一現場斟酌到能夠會湧現文件加載的毛病或許辦事器毛病後,我們的第一向覺是這不是我們代碼的成績,這是我們代碼以外的成績。
例以下面這段代碼
public void WriteSnapShot(string fileName, IEnumerable<DbItem> items) { string format = "{0}\t{1}\t{2}\t{3}\t{4}\t{5}"; using (FileStream fs = new FileStream(fileName, FileMode.Create)) { using (StreamWriter sw = new StreamWriter(fs, Encoding.Unicode)) { ... foreach (var item in items) { sw.WriteLine(string.Format(format, new object[]{ item.dealMan, item.version, item.priority, item.bugStatus, item.bugNum, item.description})); } sw.Flush(); } } }
下面的代碼在寫入文件,很明顯會招致IOException。略微有經歷的法式員都邑斟酌到IO上能夠出成績,那我們應當若何處置這個成績呢?在這個高低文中,我們別無它法,只能讓這個毛病持續往上拋,告訴下面一層的挪用者,有一個毛病產生了,至於上一層挪用者會若何處置,不是這個函數要斟酌的成績。但在這個函數中,要記得一點,將以後函數中所占用的資本釋放了。是以,當我們不克不及掌握的內部毛病湧現時,我們可以將其作為異常往上拋,這時候,我們該應用異常。
如今再來看看斷言,我們照樣以上面的一段代碼為例子。
public Entities.SimpleBugInfo GetSimpleBugInfo(string bugNum) { var selector = DependencyFactory.Resolve<ISelector>(); var list = selector.Return<Entities.SimpleBugInfo>( reader => new Entities.SimpleBugInfo { bugNum = reader["bugNum"].ToString(), dealMan = reader["dealMan"].ToString(), description = reader["description"].ToString(), size = Convert.ToInt32(reader["size"]), fired = Convert.ToInt32(reader["fired"]), }, "select * from bugInfo", new WhereClause(bugNum, "bugNum")); Trace.Assert(list != null); if (list.Count == 0) return null; else return list[0]; }
當我貼出這段代碼時,心境有些曲折,由於我自己在這裡也糾結了良久,這也是我一向未將斷言和異常劃清界限的緣由之一。
起首我們往返顧一下之前界說的斷言應用場景:外部弗成能產生的毛病。
selector.Return這段代碼是否是外部代碼?假如我們可以或許修正Return中的代碼,解釋它是外部代碼;反之,解釋它是內部代碼。關於外部代碼,我們可以用斷言來掩護其邏輯的不變性,當斷言被觸發時,我們便可以確信是外部代碼的毛病,我們應當立刻修復。
再糾結一下,假定Return是內部代碼,我們沒有方法去修正它。那末下面的代碼可以有兩種寫法(假如你有更多的設法主意,請賜教)。
第一種,直接拋出異常。
If(list == null) { throw new NullReferenceException(); }
第二種,調劑代碼。
if(list == null || list.Count == 0) { return null; } else { return list[0]; }
固然,還有一種就是甚麼也不做,讓代碼履行下去直至體系為你拋出空援用毛病。但這類做法違反了防卸性編程的准繩,我們老是應行盡早或離毛病的產生地比來的處所處置毛病,防止毛病數據流向體系的其它處所,發生加倍嚴重的毛病。
總結
對異常或斷言的應用取決於你要防卸的是一個外部毛病照樣內部毛病和你以為它是一個外部毛病或內部毛病。假如你決議防卸一個外部毛病,那請武斷應用斷言,反之,請應用異常。
異常處置
異常處置關於流程的掌握,就像拋出與捕捉一樣分為兩個方面:
假如毛病(或某種情形)產生,能否許可法式的掌握流持續履行下去(異常的拋出)
假如以後有異常產生,以後的代碼能否無機會讓法式的掌握流進入到一個公道的狀況(異常的捕捉)
我以為可以用以上兩條,作為斷定異常處置的繩尺。其實年夜家如今應當可以發明,這個所謂的繩尺的側重點在於異常關於流程的影響,而不再是在甚麼情形下才應用異常。
關於流程掌握,最直接的莫過於上面這段代碼
try { foreach (var lockGroup in lockGroups) { ... foreach (var newlock in lockGroup.ToArray()) { ... if (diningBlocks.Exists(n => testLockRange.IsOverlapped(n.StartTime, n.EndTime))) { status = LockStatus.InResourceBlock; throw new LockException(); } var diningAvail = availabilities.Find(n => n.Time == newlock.StartTime.TimeOfDay); if (diningAvail == null) { status = LockStatus.Failed; throw new LockException(); } ... if (newLockQuantity > diningAvail.MaxAvail && !canOverrideLock.AllowOverBook) { status = LockStatus.Override; throw new LockException(); } else if (newLockQuantity + reservedQuantity + currentLockedAvail > diningAvail.MaxAvail && !canOverrideLock.AllowOverBook) { status = LockStatus.Override; throw new LockException(); } ... } } } catch (LockException) { return new DiningLock[] { }; }
在下面的代碼中,有兩層for輪回,當最內層湧現某種情形時,請求停滯全部for輪回的履行,明顯用兩個break是不可的,還得參加一個幫助變量。
然則,假如用異常,這個處置就簡略多了。可以直接在最內層的拋出異常,在最外層(或是流程掌握須要的處所)捕捉異常。
在下面的代碼中,異常處置起到了流程掌握的感化,而不只僅傳遞毛病信息,對代碼的簡化做出了進獻。