C#開發(fā)人員應該知道的13件事情

1. 開發(fā)過程

開發(fā)過程是錯誤和缺陷開始的地方。使用工具可以幫助你在發(fā)布之后,解決掉一些問題。

編碼標準

遵照編碼標準可以編寫出更多可維護的代碼,特別是在由多個開發(fā)人員或團隊編寫和維護的代碼庫中。例如FxCop,StyleCop和ReSharper等,就是常用的實施編碼標準的工具。

開發(fā)人員:在壓縮代碼之前,請使用工具仔細檢查是否違反了標準,并且對結果進行分析。使用工具發(fā)現(xiàn)的代碼路徑問題,不比你預期的少。

代碼審查

代碼審查和結對編程是任務開發(fā)人員審查他人編寫的源代碼的常見做法。通過這些方式希望能夠檢查出作者的錯誤,如編碼錯誤或實現(xiàn)錯誤。

代碼審查是一個很有價值的做法,但是它依賴于人類,易犯錯誤,所以很難擴展。

靜態(tài)分析

靜態(tài)分析工具會在不運行代碼的情況下分析代碼,在不需要編寫測試用例的情況下,查找違反編碼標準或存在缺陷的問題。它們能有效地找到問題,但你需要選擇出那些能夠定位出有價值問題的工具,找出有價值的問題。C#靜態(tài)分析工具包括Coverity,CAT.NET和Visual Studio代碼分析。

動態(tài)分析

動態(tài)分析工具在運行時分析代碼,幫助你查找缺陷,如安全漏洞,性能和并發(fā)問題。它分析運行時環(huán)境的上下文中的代碼,因此其有效性受測試工作負載的限制。Visual Studio提供了一些動態(tài)分析工具,包括并發(fā)可視化器,IntelliTrace和分析工具。

管理人員/團隊領導:利用開發(fā)最佳實踐,以避免常見的陷阱。仔細考慮可用的工具,以確保它們與你的需求和文化兼容。

測試

有許多類型的測試,例如:單元測試,系統(tǒng)集成測試,性能測試,滲透測試。在開發(fā)階段,大多數(shù)測試由開發(fā)人員或測試人員編寫,以驗證應用程序是否滿足其要求。

測試僅在它們運行正確的代碼時有效。在實現(xiàn)功能和測試的同時,保持開發(fā)速度是具有挑戰(zhàn)性的。

開發(fā)最佳實踐

投入時間來識別和配置工具,以便找到你關心的代碼問題,無需為開發(fā)人員帶來更多的工作。經(jīng)常自動運行分析工具和測試,以確保開發(fā)人員在代碼剛寫完不久,就能定位到問題。

盡快地定位到所有的診斷輸出 - 無論是編譯器警告,標準違例,通過靜態(tài)分析識別的缺陷,還是測試失敗。如果新的診斷全部是可忽略的,那么審查所起的作用就增加了,開發(fā)人員也不必再為代碼問題煩惱。

采用這些最佳實踐有助于提高代碼的質(zhì)量,安全性和可維護性,開發(fā)人員的一致性和生產(chǎn)力以及發(fā)布的可預測性。

2. 類型陷阱

C#的一個主要優(yōu)勢是其靈活的類型系統(tǒng);?類型安全有助于早期發(fā)現(xiàn)錯誤。通過強制實施嚴格的類型規(guī)則,編譯器能夠幫助你保持正確的編碼實踐。C#語言和.NET框架提供了豐富的類型集合以適應最常見的需求。大多數(shù)開發(fā)人員很好地了解常見的類型及其用途,但有一些常見的誤解和誤用。

有關.NET Framework類庫的更多信息可以在MSDN庫中找到。

了解和使用標準接口

某些接口涉及常用的C#特性。例如,IDisposable允許使用常用的資源處理習語,例如“using”關鍵字。理解什么時候使用接口,能夠使你編寫更容易維護的C#代碼。

避免ICloneable - 設計者從來沒有明確拷貝的對象是深拷貝還是淺拷貝。由于沒有正確拷貝對象行為的標準,也就無法有效的使用這樣的接口。

結構

盡量避免寫到結構體。將它們視為不可變的,能夠防止混淆的發(fā)生,并且在共享內(nèi)存的場景(如多線程應用程序)下更安全。相反,在創(chuàng)建結構體時使用初始化對象,如果需要更改值,則創(chuàng)建新的實例。

要了解哪些標準類型/方法是不可變的并返回新值(例如,string,DateTime)和哪些是可變的(List.Enumerator)。

字符串

字符串可以為null,因此在適當時,使用起來很方便。等價(s.Length == 0)可能會拋出一個NullReferenceException,但是String.IsNullOrEmpty(s)和String.IsNullOrWhitespace(s)函數(shù)能夠優(yōu)雅地處理null。

標記枚舉

枚舉類型和常量值是能表露出自己含義的標識符,用于替換魔術數(shù)字,以便使得代碼更加可讀。

如果你發(fā)現(xiàn)需要創(chuàng)建枚舉的集合,標記枚舉可能是一個更簡單的選擇:

public enum Tag {

? None=0x0,

? Tip=0x1,

? Example=0x2

}

這使你能夠輕松地為代碼段添加多個標簽:

snippet.Tag = Tag.Tip | Tag.Example

這可以改善數(shù)據(jù)封裝,因為你不必擔心通過Tag property getter暴露內(nèi)部集合。

等價比較

有兩種類型的等價:

引用相等,這意味著兩個引用,引用了同一個對象。

值平等,這意味著兩個不同的對象是等值的。

此外,C#提供了多種方法來測試等價。最常見的方法是使用:

==和!=運算符

繼承自Object的虛擬Equals方法

靜態(tài)Object.Equals方法

IEquatable接口的Equals方法

靜態(tài)Object.ReferenceEquals方法

可能難以知道預期的是引用相等還是值相等。如果你重寫Equals,不要忘記IEquatable ,GetHashCode(),如MSDN中所述。

注意無類型容器對重載的影響。考慮比較“myArrayList [0] == myString”。數(shù)組列表元素是編譯時類型“對象”,因此使用引用等價。C#編譯器會警告你這個潛在錯誤,但是有許多類似的情況,編譯器不會對意外的引用相等發(fā)出警告。

3. 類陷阱

封裝你的數(shù)據(jù)

類負責正確地管理數(shù)據(jù)。出于性能原因,它們通常緩存部分結果或者對其內(nèi)部數(shù)據(jù)的一致性做出假設。數(shù)據(jù)公開訪問會影響你緩存或做出假設的能力,對性能,安全性和并發(fā)性都有潛在影響。例如,暴露可變成員,如通用集合和數(shù)組,允許用戶在你不知情的情況下修改這些結構。

屬性

屬性使你能夠精確控制用戶如何與你的對象進行交互,除了你通過訪問修改器控制的之外。具體來說,屬性使你能夠控制讀取和寫入時發(fā)生的情況。

屬性使你能夠建立穩(wěn)定的API,同時重寫getter和setter中的數(shù)據(jù)訪問邏輯,或提供數(shù)據(jù)綁定源。

不要也不要讓屬性獲取器拋出異常,避免修改對象狀態(tài)。這樣就意味著需要一種方法而不是屬性獲取器。

有關屬性的詳細信息,請參閱MSDN的屬性設計主題:http://msdn.microsoft.com/en-us/library/ms229006(v=vs.120).aspx

仔細的使用getters,因為它有副作用。開發(fā)者認為成員訪問是一個微不足道的操作,所以他們經(jīng)常忘記在代碼審查期間考慮帶來的副作用。

對象初始化

你可以在創(chuàng)建表達式時,對新創(chuàng)建的對象設置屬性。使用特定值來創(chuàng)建Class Cde 對象,并用到Foo和Bar屬性:

new C {Foo=blah, Bar=blam}

你還可以使用特定的屬性名稱,創(chuàng)建匿名類型的實例:

var myAwesomeObject =new {Name=”Foo”, Size=10};

初始化會在構造主體運行之前執(zhí)行,確保在進入構造器之前字段已經(jīng)初始化了。因為構造函數(shù)還沒有運行,所以字段初始化器不能以任何方式引用“this”。

過度指定輸入?yún)?shù)

為了幫助防止特定方法的過度使用,請嘗試采用方法所需的最小特定類型。例如,考慮一個迭代List 的方法:

public void Foo(List<Bar> bars)

{

foreach(var b in bars)

{//do something with the bar...}

}

對于其他的IEnumerable 集合,這段代碼能夠很好地運行,但是通過為參數(shù)指定List ,你就需要集合必須是一個List。選擇參數(shù)的最小特定類型(IEnumerable ,ICollection 等),以確保方法的最大有用性

4. 泛型

泛型是一種十分有效的方式,來定義與類型無關的結構體和確保類型安全的算法。

使用諸如List 之類的泛型集合,而不是無類型的集合如ArrayList,能夠提高類型的安全性和性能。

當實現(xiàn)泛型類型時,可以使用“default”關鍵字來獲取那種無法硬編碼到實現(xiàn)中的默認值。具體來說就是,數(shù)字類型的默認值為0;?引用和可空值類型的默認值為null。

T t =default(T);

5. 類型轉化

有兩種類型的conversions轉化。顯式轉換必須由開發(fā)人員調(diào)用,隱式轉換由編譯器基于上下文來應用。

類型轉化時,經(jīng)常會遇到以下兩種情形:

表達式的運行時類型比編譯器能推斷出的類型更加具體。轉換指示編譯器將表達式當做更具體的類型來處理。如果你的假設不正確,編譯器將拋出異常的代碼。例如,從對象到字符串的轉換。

轉換指示編譯器會生成關聯(lián)表達式的值的代碼,如果沒有生成,則會拋出異常。例如,從double到integer的轉換。

兩種類型轉換都是很危險的。第一種類型的轉換提出了一個問題,“為什么開發(fā)人員知道,而編譯器不知道?”如果在這種情況下,嘗試更改程序,以便編譯器可以成功地推導出正確的類型。如果你認為一個對象的運行時類型可能比編譯時類型更具體,那么你可以使用“is”或“as”運算符。

第二種類型轉換引發(fā)了一個問題,“為什么操作是在開始的地方執(zhí)行的,而不是在目標數(shù)據(jù)類型?”如果你需要一個int類型的結果,使用int比double更有意義。

有關其他想法,請參閱:http//blogs.msdn.com/b/ericlippert/archive/tags/cast+operator/

在顯式轉換是正確的操作情況下,通過使用適當?shù)倪\算符來提高可讀性,調(diào)試能力和可測試性。

6. 異常

異常不是條件

異常通常不應用于控制程序流;?它們代表的是,在運行時你可能無法恢復的意外情況。如果你預期你應該處理的情況,主動檢查情況,而不是等待異常發(fā)生。

要將格式不正確的字符串正常轉換為數(shù)字,請使用TryParse()方法;?而不是拋出異常,它返回一個布爾值,指示解析是否成功。

使用異常處理范圍

在catch內(nèi)部寫代碼,并且仔細處理成程序塊。已執(zhí)行過的代碼已經(jīng)不存在這些異常。例如:

Frobber originalFrobber =null;

try{? ? ? ? ??

? ? ? ?originalFrobber=this.GetCurrentFrobber();

? ? ? ?this.UseTemporaryFrobber();

? ? ? ?this.frobSomeBlobs();

}

finally{

? ? ? ? ? ? this.ResetFrobber(originalFrobber);

}

如果GetCurrentFrobber()拋出異常,那么當finally block被執(zhí)行時,originalFrobber仍然為null;

明智的處理異常

只捕獲你準備處理的特定異常,并且只針對特定代碼段。除非你的意圖只是簡單的記錄并重新拋出異常。某些例外可能使應用程序處于一種狀態(tài),那么就需要避免處理所有異常或根類異常的實例。最好是在沒有進一步損壞的情況下應用已經(jīng)崩潰,而不是試圖恢復并造成損害。你的恢復嘗試可能會在不經(jīng)意間使事情更糟。

處理致命異常有一些細微差別,特別是關于finally block執(zhí)行時,如何影響異常安全和調(diào)試器。有關詳情,請參閱:http://incrediblejourneysintotheknown.blogspot.com/2009/02/fatal-exceptions-and-why-vbnet-has.html

使用最高級異常處理,來安全到處理程序的意外情況并公開信息以幫助調(diào)試問題。請謹慎使用catch塊來解決本可以安全處理的特定情況,為無法預料的異常預留最高級的處理。

如果你捕獲到一個異常,那么就需要采取一些措施來處理。不計其它后果地處理當前異常只會使問題難以識別和調(diào)試。

對于公開了工作API的代碼來說,將異常包含于自定義異常中,是特別有用的。異常是方法的可見接口的一部分,應該與參數(shù)和返回值一起被控制。可能導致更多異常的方法,是不應該被使用在可維護解決方案中的。

拋出和重新拋出異常

當你希望在更深層次處理一個捕獲到的異常時,維護原始異常狀態(tài)和堆棧對于調(diào)試有極大的幫助。需要仔細地平衡,調(diào)試和安全注意事項。

簡單的重新拋出異常也是一個好選擇:

throw;

或者在新的throw中使用異常作為InnerException:

throw new CustomException(...,ex);

不要顯式地重新拋出捕獲的異常,如下所示:

throw e;

這將復位異常狀態(tài)到當前行,并且阻止調(diào)試。

一些異常發(fā)生在代碼的上下文之外。對于這些情況,你可能需要添加事件的處理程序,如ThreadException或UnhandledException,而不是使用catch塊。例如,表單處理程序線程的上下文中引發(fā)的Windows窗體異常。

數(shù)據(jù)完整性

異常不得影響數(shù)據(jù)模型的完整性。你需要確保你的對象處于一致的狀態(tài) - 不會違反類實現(xiàn)所做的任何假設。否則,通過“恢復”,你只能使你的代碼變得混亂,之后還會導致進一步的損害。

7. 事件

事件和代理相互協(xié)助,當事件發(fā)生時,為類提供了一種方法來通知用戶。事件類似于委托類型的字段;?當創(chuàng)建對象時,它們將自動初始化為null。

事件的值是一個多級代理。也就是一個可以依次調(diào)用其他代理的代理。你可以為事件分配委托;?可以通過+ =和 - =等操作符操作事件。

注意競逐條件

如果事件在線程之間共享,則有可能在你檢查null之后并且在調(diào)用它之前,另一個線程將刪除所有參數(shù) – 就會拋出NullReferenceException異常。

標準解決方案是創(chuàng)建事件的本地副本,用于測試和調(diào)用。你仍然需要小心,在其他線程中刪除的任何參數(shù),在他們的委托被意外調(diào)用時會正常運行。你還可以實施鎖定,以一種能夠避免問題的方式為操作排隊列。

public event EventHandler SomethingHappened;

private void OnSomethingHappened()

{

//The event is null until somebody hooks up to it

//Create our own copy of the event to protect against another thread removing our subscribers

EventHandler handler =SomethingHappened;

if(handler !=null)

? ? handler(this,newEventArgs());

}

更多關于時間和競逐的信息,請參閱:

http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx

8. 屬性

屬性提供了一種方法,用于將組件,類和屬性的元數(shù)據(jù)與其屬性的信息一起輸入。它們通常用于向代碼用戶提供信息,如代碼調(diào)試器,測試框架和應用程序。你可以定義自己使用的屬性,也可以使用表中列出的預定義屬性。

小心使用DebuggerStepThrough屬性,如果應用了這個屬性,會導致很難在方法中找到bug,因為你不能單步執(zhí)行或打斷它們!

9. 調(diào)試

調(diào)試是任何開發(fā)工作中重要的組成部分。除了提供對運行時環(huán)境的常規(guī)不透明方面的可見性之外,調(diào)試器可以進入運行時環(huán)境,同時調(diào)試器還會導致應用程序的在沒有調(diào)試器的情況下,獲的不同的結果。

使異常堆棧可見

要查看當前框架的異常狀態(tài),可以在Visual Studio Watch窗口中添加表達式“$ exception”。此變量包含當前異常狀態(tài),類似于你在catch塊中看到的情況,除非你可以在調(diào)試器中看到異常狀態(tài),否則就不必在代碼中實際捕獲異常。

注意訪問器中的副作用

如果你所使用的屬性有副作用,請考慮是否應使用屬性或調(diào)試器設置,來防止調(diào)試器自動調(diào)用getter。例如,你的類可能具有這些屬性:

private int remainingAccesses =10;

private string meteredData;

public string MeteredData

{

? ?get

? ?{

? ?if(remainingAccesses-- >0)

? ? ? ?returnmeteredData;

? ? ? ?returnnull;

}

}

第一次在調(diào)試器中查看此對象時,remainingAccesses將顯示為值10,MeteredData顯示為null。如果你將鼠標懸停在remainingAccesses上,你會看到它的值現(xiàn)在是9。調(diào)試器顯示的屬性值已經(jīng)改變了對象的狀態(tài)。

10.優(yōu)化

早做計劃,經(jīng)常衡量,然后優(yōu)化

在設計期間設置合理的性能目標。在開發(fā)期間,專注于正確性而不是細微優(yōu)化。經(jīng)常根據(jù)目標衡量你的效果。如果你沒有達到目標,則應該花費時間來優(yōu)化程序。

始終采用最合適的工具,在具有可重復性和盡可能接近用戶所經(jīng)歷的實際條件的情況下,對性能進行經(jīng)驗性測量。

由于CLR優(yōu)化,有時效率低下的代碼實際上比高效的代碼運行速度更快。例如,CLR優(yōu)化覆蓋了整個數(shù)組的循環(huán),以避免隱式的單元范圍檢查。開發(fā)人員通常在循環(huán)數(shù)組之前計算長度:

int[] a_val =int[4000];

int len =a_val.Length;

for(inti =0; i < len; i++)

? ?a_val[i]= i;

通過將長度放在變量中,CLR可能無法識別模式,并將跳過優(yōu)化。手動優(yōu)化違反了直覺,會導致性能較差。

構建字符串

如果你要做很多字符串連接,應該使用System.Text.StringBuilder對象,這樣可以避免構建許多臨時字符串對象。

對集合使用批處理操作

如果需要創(chuàng)建和填充已知大小的集合,請在創(chuàng)建集合時保留空間,以避免由于重復重新分配而導致的性能和資源問題。你可以使用AddRange方法(如List 中的方法)進一步提高性能:

Persons.AddRange(listBox.Items);

11.資源管理

垃圾回收器能夠自動清理內(nèi)存。即使如此,所有一次性資源,也必須妥善處理 - 特別是那些不由垃圾收集器管理的資源。

使用try / finally塊來確保資源正確釋放,或讓你的類實現(xiàn)IDisposable,并利用更清潔和更安全的using語句。

using(StreamReader reader=new StreamReader(file))

{

? ? //your code here

避免代碼中使用垃圾收集器

盡量不要通過調(diào)用GC.Collect()干擾垃圾收集器,而應該將重點放在正確釋放或處置資源。當測量性能時,如果你能夠正確的評估影響,在小心的讓垃圾收集器運行。

避免編寫終結器

不同于最流行的錯誤認知,你的類不需要一個Finalizer,僅僅是因為它實現(xiàn)IDisposable!你可以實現(xiàn)IDisposable以使你的類能夠在任何所有的復合實例上調(diào)用Dispose,但是終結器只應在直接擁有非托管資源的類上實現(xiàn)。

Finalizer主要用于調(diào)用interop API,來處理Win32句柄,SafeHandle更容易處理。

你不能推測你的終結器 - 它總是在終結器線程上運行 - 可以安全地與其他對象交互。那些其他對象本身可能已經(jīng)完成了。

12.并發(fā)

并發(fā)和多線程編程是一件很復雜和困難的事情。在向應用程序添加并發(fā)之前,請確保你真正了解自己正在做什么 - 有很多細微之處需要了解!

多線程應用程序非常難以推理,并且容易受到諸如通常不影響單線程應用程序的競爭條件和死鎖等問題的影響。鑒于這些風險,你應該最后才考慮多線程。如果你必須使用多個線程,請盡量通過不在線程之間共享內(nèi)存來最小化同步的需要。如果必須同步線程,請使用最高級別的同步機制。

最高級別,這些機制包括:

Async-await/Task Parallel Library/Lazy<T>

Lock/monitor/AutoResetEvent

Interlocked/Semaphore

Volatile fields and explicit barriers

C#/ .NET中并發(fā)的復雜性很難就在這里解釋清楚。如果你想要或需要開發(fā)一個利用并發(fā)的應用程序,請查看詳細的文檔,如O'Reilly的“Concurrency in C# Cookbook”。

使用volatile

將字段標記為“易變”是高級功能,即使專家也經(jīng)常誤解。C#編譯器將確保訪問字段具有獲取和釋放語義;?這不同于確保對該字段的所有訪問都處于鎖定狀態(tài)。如果你不知道什么是獲取和釋放語義,以及它們?nèi)绾斡绊慍PU級優(yōu)化,則應避免使用volatile字段。相反,應該使用較高級別的工具,如任務并行庫或CancellationToken類型。

利用線程安全的內(nèi)置方法

標準庫類型通常提供方便線程安全訪問對象的方法。例如,Dictionary.TryGetValue()。使用這些方法通常使你的代碼更清潔,你不需要擔心如TOCTTOU or TOCTOU場景等數(shù)據(jù)競爭的情況。

不要鎖定“this”,字符串或其他常見的公共對象

當實現(xiàn)在多線程上下文中使用的類時,要非常小心使用鎖。鎖定此字符串或其他公共對象,會阻止封裝鎖定狀態(tài),并可能導致死鎖。你需要防止其他代碼鎖定你的實現(xiàn)上正在使用的對象;?最安全的做法是使用一個私人的對象成員。

13.避免常見錯誤

引用null

不適當?shù)氖褂胣ull,是編碼缺陷的常見來源,可能會導致程序崩潰和其它意外行為。如果你嘗試訪問一個空引用,以為它是一個對象的有效引用一樣 - 例如,通過訪問一個屬性或方法,運行時將拋出一NullReferenceException異常。

靜態(tài)和動態(tài)分析工具可以幫助你在發(fā)布代碼之前識別潛在的NullReferenceException異常。在C#中,空引用通常由尚未引用對象的變量引起。對于空值類型和引用類型來說,Null是一個有效值。例如,Nullable <T> ,空委托,取消訂閱事件,會在“as”轉換,以及在許多其他情況下失敗。

每個空引用異常是都一個錯誤。不應該去捕獲NullReferenceException,而應該嘗試在使用它們之前測試對象是否為null。這也使得代碼更容易被最小化try / catch塊讀取。

從數(shù)據(jù)庫表中讀取數(shù)據(jù)時,請確保,缺失值可以表示為DBNull對象,而不是空引用。不要指望它們表現(xiàn)的像潛在的空引用。

將十進制值替換為二進制數(shù)

浮點數(shù)和雙精度表示二進制有理數(shù),不是小數(shù)有理數(shù),在存儲十進制值時必須使用二進制的近似值。從十進制的角度來看,這些二進制近似具有不一致的舍入和精度 - 有時導致算術運算的意外結果。因為浮點運算通常在硬件中執(zhí)行,硬件條件可能會不可預測地加劇這些差異。

當小數(shù)精度非常重要時,使用十進制,就像財務計算等情況。

修改結構

一個常見的錯誤情況是忘記結構體是值類型的,這就意味著它們被復制了并且通過值來進行傳遞。假設你有這樣的代碼:

struct P {public int x;public int y; }

voidM()

{

P p=whatever;

p.x=something;

N(p);

有一天,維護者決定將代碼重構為:

voidM()

{

P p=whatever;

Helper(p);

N(p);

}

void Helper(P p)

{

p.x= something;

現(xiàn)在當在M()中調(diào)用N(p)時,p具有錯誤的值。調(diào)用助手(p)傳遞p的副本,而不是p的引用,因此Helper()中執(zhí)行的變化將丟失。相反,Helper會返回修改的p的副本。

意外的算術

C#編譯器保護你出現(xiàn)常量的算術溢出,但不一定是計算值。

忽略保存返回值

與結構體不同,類是引用類型,方法可以修改引用的對象。然而,不是所有的對象方法都實際修改了引用的對象,一些會返回一個新對象。當開發(fā)人員調(diào)用后者時,他們需要記住將返回值賦給變量,以便使用修改后的對象。在代碼審查期間,這種類型的問題通常在會被發(fā)現(xiàn)。一些對象,如字符串,是不可變的,所以方法從不修改這些對象。即使如此,開發(fā)人員也會通常忘記。

例如,考慮string.Replace():

stringlabel = “My nameisAloysius”;

label.Replace(“Aloysius”, “secret”);

代碼打印“我的名稱是Aloysius”,因為Replace方法不修改字符串。

不要使迭代器/枚舉器變得無效

不要在迭代時修改集合。

List myItems =new List{20,25,9,14,50};

foreach(int item in myItems)

{

if(item <10)

{

myItems.Remove(item);

//iterator is now invalid!

//you’ll get an exception on the next iteration

如果你運行這個代碼,一旦循環(huán)到集合中的下一個項目時。你會收到一個異常拋出。

正確的解決方案,是使用第二個列表來保存你要刪除的項目,然后在刪除時迭代該列表:

List<Int> myItems =new List<Int>{20,25,9,14,50};

List<Int> toRemove =new List<Int>();

foreach(int item in myItems)

{

if(item <10)

{

toRemove.Add(item);

}

}foreach(intitemintoRemove)

{

或者如果你使用C#3.0或更高版本,你可以使用List<T> ?.RemoveAll。

就像這樣:

myInts.RemoveAll(item => (item <10));

屬性名稱錯誤

在實現(xiàn)屬性時,請注意屬性名稱不同于類中使用的數(shù)據(jù)成員。在訪問屬性時,容易意外使用相同的名稱,并導致出現(xiàn)無限遞歸的情況。

//The following code will trigger infinite recursion

private string name;

public string Name

{

get

{

returnName;//should reference “name” instead.

當重命名間接屬性時要小心。例如,WPF中的數(shù)據(jù)綁定,會將屬性名稱指定為字符串。如果不小心更改該屬性名稱,你將會無意中創(chuàng)建了一個編譯器無法防護的問題。

以上就是所有C#開發(fā)人員應該知道的13件事情。

了解了C#開發(fā)中應該知道的13件事情,有助于我們更好地使用C#進行開發(fā),當然在開發(fā)時,也可以借助一些使用C#編寫的開發(fā)工具。如ComponentOne Studio Enterprise,這是一款專注于企業(yè)應用的.NET全功能控件套包,支持WinForms、WPF、UWP、ASP.NET MVC等多個平臺,幫助、在縮減成本的同時,提前交付豐富的桌面、Web和移動企業(yè)應用。

原文鏈接:https://dzone.com/refcardz/csharp

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,278評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,241評論 2 375

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,807評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,692評論 25 708
  • 1.開發(fā)流程 程序的Bug與瑕疵往往出現(xiàn)于開發(fā)流程當中。只要對工具善加利用,就有助于在你發(fā)布程序之前便將問題發(fā)現(xiàn),...
    芭蕾武閱讀 827評論 0 0
  • 小梅子姐姐:你的孩子馬上就要上幼兒園了,或者你的孩子已經(jīng)上了幼兒園,可是你對孩子上幼兒園依舊會存在許多讓你困惑和擔...
    小梅子姐姐閱讀 2,705評論 1 16
  • 任人宰割的羔羊啊 你怕了嗎 怕就躲到夜里吧 這里有黑暗但沒有恐懼 誰也看不到你 你可以在這里安眠 千夫所指的罪惡啊...
    年輕的風閱讀 217評論 2 0