<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C#編程中最常見的10個錯誤

          共 13905字,需瀏覽 28分鐘

           ·

          2021-08-06 03:02




          原文來自互聯(lián)網(wǎng),由長沙DotNET技術(shù)社區(qū)編譯。如譯文侵犯您的署名權(quán)或版權(quán),請聯(lián)系小編,小編將在24小時內(nèi)刪除。限于譯者的能力有限,個別語句翻譯略顯生硬,還請見諒。

          原文來自:https://www.toptal.com/c-sharp/top-10-mistakes-that-c-sharp-programmers-make

          作者簡介:

          帕特里克·賴德(PATRICK RYDER)在Microsoft工作期間幫助創(chuàng)建了VB 1.0和更高版本的.NET平臺。自2000年以來,他專注于全棧開發(fā)。

          C#是針對Microsoft 公共語言運行庫(CLR)的幾種語言之一。面向CLR的語言受益于多種功能,例如跨語言集成和異常處理,增強的安全性,簡化的組件交互模型以及調(diào)試和性能分析服務(wù)。在當(dāng)今的CLR語言中,C#被廣泛用于針對Windows臺式機,移動或服務(wù)器環(huán)境的復(fù)雜,專業(yè)的開發(fā)項目中。(譯者注,目前已支持各類跨平臺的操作系統(tǒng)環(huán)境)

          C#是一種面向?qū)ο蟮膹婎愋驼Z言。在編譯和運行時,C#中嚴(yán)格的類型檢查會導(dǎo)致盡早報告大多數(shù)典型的C#編程錯誤,并準(zhǔn)確定位其位置。這可以在C Sharp編程中節(jié)省大量時間,相比之下,在更自由地執(zhí)行類型安全的語言中,跟蹤令人困惑的錯誤的原因可能會在違規(guī)操作發(fā)生很久之后才發(fā)生。但是,許多C#編碼人員無意間(或不小心)放棄了這種檢測的好處,這導(dǎo)致了本C#教程中討論的一些問題。

          關(guān)于本C Sharp編程教程

          本教程描述了C#程序員犯下的10種最常見的C#編程錯誤或應(yīng)避免的問題,并為他們提供了幫助。

          盡管本文中討論的大多數(shù)錯誤都是C#特定的,但有些錯誤也與其他以CLR為目標(biāo)或使用框架類庫(FCL)的語言有關(guān)。

          常見的C#編程錯誤#1:使用值類型與引用相等,或反過來

          C ++和許多其他語言的程序員習(xí)慣于控制他們分配給變量的值是簡單的值還是對現(xiàn)有對象的引用。但是,在C Sharp編程中,該決定由編寫對象的程序員決定,而不是由實例化該對象并將其分配給變量的程序員做出。對于那些試圖學(xué)習(xí)C#編程的人來說,這是一個常見的“陷阱”。

          如果您不知道所使用的對象是值類型還是引用類型,則可能會遇到一些意外。例如:

                Point point1 = new Point(20, 30);      Point point2 = point1;      point2.X = 50;      Console.WriteLine(point1.X);       // 20 (does this surprise you?)      Console.WriteLine(point2.X);       // 50
          Pen pen1 = new Pen(Color.Black); Pen pen2 = pen1; pen2.Color = Color.Blue; Console.WriteLine(pen1.Color); // Blue (or does this surprise you?) Console.WriteLine(pen2.Color); // Blue

          正如你所看到的,Point和Pen對象創(chuàng)建方式不盡相同,但值point1保持不變,當(dāng)一個新的X坐標(biāo)值被分配到point2,一個新的顏色被分配到修改pen2。因此,我們可以推斷出,point1并且point2每個Point對象都包含自己的對象副本,而pen1和pen2都包含對同一Pen對象的引用。

          但是,如果不進(jìn)行此實驗,我們怎么知道呢?


          答案是查看對象類型的定義(您可以在Visual Studio中通過將光標(biāo)置于對象類型的名稱上并按F12輕松地完成此操作):


                public struct Point { ... }     // defines a “value” type      public class Pen { ... }        // defines a “reference” type

          如上所示,在C#編程中,struct關(guān)鍵字用于定義值類型,而class關(guān)鍵字用于定義引用類型。

          對于那些具有C ++背景的人,由于C ++和C#關(guān)鍵字之間的許多相似之處而陷入一種錯誤的安全感,這種行為可能會讓人感到意外,您可能會從C#教程中尋求幫助。

          如果您要依賴值和引用類型之間不同的某些行為(例如,將對象作為方法參數(shù)傳遞并讓該方法更改對象狀態(tài)的能力),請確保您正在處理正確的對象類型,以避免C#編程問題。


          常見的C#編程錯誤#2:誤解了未初始化變量的默認(rèn)值

          在C#中,值類型不能為null。根據(jù)定義,值類型具有值,甚至值類型的未初始化變量也必須具有值。這稱為該類型的默認(rèn)值。當(dāng)檢查變量是否未初始化時,這會導(dǎo)致以下結(jié)果,通常是意外的結(jié)果:

                class Program {          static Point point1;          static Pen pen1;          static void Main(string[] args) {              Console.WriteLine(pen1 == null);      // True              Console.WriteLine(point1 == null);    // False (huh?)          }      }

          為什么point1不為空?答案是Point是值類型,它的默認(rèn)值為Point(0,0),而不是null。未能意識到這一點是在C#中非常容易(也是常見)的錯誤。許多(但不是全部)值類型都有一個IsEmpty屬性,您可以檢查該屬性是否等于其默認(rèn)值:

          Console.WriteLine(point1.IsEmpty);        // True

          當(dāng)您檢查變量是否已初始化時,請確保您知道該類型的未初始化變量在默認(rèn)情況下將具有什么值,并且不要依賴于它為null。

          常見的C#編程錯誤#3:使用不正確或未指定的字符串比較方法

          比較C#中的字符串有很多不同的方法。

          盡管許多程序員使用==運算符進(jìn)行字符串比較,但這實際上是最不希望采用的方法之一,主要是因為它沒有在代碼中明確指定需要哪種類型的比較。

          相反,在C#編程中測試字符串相等性的首選方法是使用以下Equals方法:

            public bool Equals(string value);
          public bool Equals(string value, StringComparison comparisonType);

          第一個方法簽名(即不帶comparisonType參數(shù))實際上與使用==運算符相同,但是具有顯式應(yīng)用于字符串的好處。它執(zhí)行字符串的序數(shù)比較,基本上是逐字節(jié)比較。在很多情況下,這正是您想要的比較類型,尤其是在比較以編程方式設(shè)置值的字符串(例如文件名,環(huán)境變量,屬性等)時。在這些情況下,只要序數(shù)比較確實是正確的類型這種情況下的比較,使用Equals方法不帶 comparisonType參數(shù)的唯一缺點是,閱讀代碼的人可能不知道您要進(jìn)行哪種類型的比較。

          但是,使用Equals每次比較字符串包含comparisonType的方法簽名,不僅可以使代碼更清晰,還可以使您明確考慮需要進(jìn)行哪種類型的比較。這是一件值得做的事情,因為即使英語在序數(shù)比較和對文化敏感的比較之間不能提供很多差異,其他語言也可以提供很多好處,而忽略其他語言的可能性正在為您提供巨大的潛力錯誤的道路。例如:

                string s = "strasse";
          // outputs False: Console.WriteLine(s == "stra?e"); Console.WriteLine(s.Equals("stra?e")); Console.WriteLine(s.Equals("stra?e", StringComparison.Ordinal)); Console.WriteLine(s.Equals("Stra?e", StringComparison.CurrentCulture)); Console.WriteLine(s.Equals("stra?e", StringComparison.OrdinalIgnoreCase));
          // outputs True: Console.WriteLine(s.Equals("stra?e", StringComparison.CurrentCulture)); Console.WriteLine(s.Equals("Stra?e", StringComparison.CurrentCultureIgnoreCase));

          最安全的做法是始終為該Equals方法提供comparisonType參數(shù)。以下是一些基本準(zhǔn)則:

          ?在比較用戶輸入的字符串或要顯示給用戶的字符串時,請使用區(qū)分區(qū)域性的比較(CurrentCulture或CurrentCultureIgnoreCase)。?比較程序字符串時,請使用序數(shù)比較(Ordinal或OrdinalIgnoreCase)。?InvariantCulture和InvariantCultureIgnoreCase一般不被除了在非常有限的情況下使用,因為順序比較是更有效的。如果需要進(jìn)行文化意識比較,則通常應(yīng)針對當(dāng)前文化或其他特定文化進(jìn)行比較。

          除了Equals方法之外,字符串還提供了 Compare方法,該方法為您提供有關(guān)字符串相對順序的信息,而不僅僅是進(jìn)行相等性測試。此方法是優(yōu)選的<,<=,>和>=運算符,對于上述的為討論避免C#的問題同樣的原因。

          常見的C#編程錯誤#4:使用迭代(而不是聲明性)語句來操作集合

          在C#3.0中,向語言[1]添加語言集成查詢[2](LINQ)永遠(yuǎn)改變了查詢和操作集合的方式。從那時起,如果您使用迭代語句來操作集合,那么您本來應(yīng)該使用LINQ。

          一些C#程序員甚至不知道LINQ的存在,但是幸運的是,這個數(shù)目正在變得越來越小。但是,許多人仍然認(rèn)為,由于LINQ關(guān)鍵字和SQL語句之間的相似性,它的唯一用途是在查詢數(shù)據(jù)庫的代碼中。

          盡管數(shù)據(jù)庫查詢是LINQ語句的一種非常普遍的用法,但它們實際上是在任何可枚舉的集合(即,實現(xiàn)IEnumerable接口的任何對象)上工作的。因此,例如,如果您有一個Accounts數(shù)組,而不是為每個each編寫一個C#List:

                decimal total = 0;      foreach (Account account in myAccounts) {        if (account.Status == "active") {          total += account.Balance;        }      }你可以這樣寫:      decimal total = (from account in myAccounts                       where account.Status == "active"                       select account.Balance).Sum();

          盡管這是一個非常簡單的示例,說明如何避免這種常見的C#編程問題,但在某些情況下,單個LINQ語句可以輕松替換代碼中的迭代循環(huán)(或嵌套循環(huán))中的數(shù)十個語句。更少的通用代碼意味著更少的引入錯誤的機會。但是請記住,在性能方面可能會有所取舍。在對性能有嚴(yán)格要求的情況下,尤其是在迭代代碼能夠?qū)INQ無法進(jìn)行的集合進(jìn)行假設(shè)的情況下,請確保在這兩種方法之間進(jìn)行性能比較。

          常見的C#編程錯誤#5:無法考慮LINQ語句中的基礎(chǔ)對象

          LINQ非常適合抽象處理集合的任務(wù),無論它們是內(nèi)存中對象,數(shù)據(jù)庫表還是XML文檔。在理想環(huán)境中,您不需要知道底層對象是什么。但是這里的錯誤是假設(shè)我們生活在一個完美的世界中。實際上,如果相同的LINQ語句恰好采用不同的格式,則當(dāng)它們對完全相同的數(shù)據(jù)執(zhí)行時,它們可以返回不同的結(jié)果。

          例如,考慮以下語句:

                decimal total = (from account in myAccounts                       where account.Status == "active"                       select account.Balance).Sum();

          如果對象的其中一個account.Status等于“活動”(請注意大寫字母A)會怎樣?好吧,如果myAccounts是一個DbSet對象(使用默認(rèn)的不區(qū)分大小寫的默認(rèn)配置設(shè)置),則where表達(dá)式仍會匹配該元素。但是,如果myAccounts位于內(nèi)存陣列中,則它將不匹配,因此將產(chǎn)生總計不同的結(jié)果。等一下 在前面討論字符串比較時,我們看到==運算符對字符串進(jìn)行了序數(shù)比較。那么,為什么在這種情況下==操作員執(zhí)行不區(qū)分大小寫的比較?


          答案是,當(dāng)LINQ語句中的基礎(chǔ)對象是對SQL表數(shù)據(jù)的引用時(如本示例中的Entity Framework DbSet對象一樣),該語句將轉(zhuǎn)換為T-SQL語句。然后,操作員將遵循T-SQL編程規(guī)則,而不是C#編程規(guī)則,因此,上述情況下的比較最終不區(qū)分大小寫。


          通常,即使LINQ是查詢對象集合的有用且一致的方式,實際上,您仍然需要知道您的語句是否將轉(zhuǎn)換為C#以外的其他內(nèi)容,以確保代碼的行為能夠在運行時達(dá)到預(yù)期。

          常見的C#編程錯誤#6:擴展方法使您感到困惑或冒充

          如前所述,LINQ語句可在實現(xiàn)IEnumerable的任何對象上工作。例如,以下簡單功能將在任何帳戶集合上累加余額:

                public decimal SumAccounts(IEnumerable<Account> myAccounts) {          return myAccounts.Sum(a => a.Balance);      }

          在上面的代碼中,myAccounts參數(shù)的類型聲明為 IEnumerable。由于myAccounts引用Sum方法(C#使用熟悉的“點符號”來引用類或接口上的方法),因此我們希望看到Sum()在IEnumerable接口定義上調(diào)用的方法。但是,定義 IEnumerable未引用任何Sum方法,而只是這樣:

                public interface IEnumerable<out T> : IEnumerable {          IEnumerator<T> GetEnumerator();      }

          那么該Sum()方法在哪里定義?C#是強類型的,因此,如果對該Sum方法的引用無效,則C#編譯器肯定會將其標(biāo)記為錯誤。因此,我們知道它必須存在,但是在哪里?此外,LINQ為查詢或匯總這些集合提供的所有其他方法的定義在哪里?答案是這Sum()不是IEnumerable接口上定義的方法 。相反,它是在System.Linq.Enumerable類上定義的靜態(tài)方法(稱為“擴展方法”):

                namespace System.Linq {        public static class Enumerable {          ...          // the reference here to “this IEnumerable<TSource> source” is          // the magic sauce that provides access to the extension method Sum          public static decimal Sum<TSource>(this IEnumerable<TSource> source,                                             Func<TSource, decimal> selector);          ...        }      }

          那么,什么使擴展方法與任何其他靜態(tài)方法不同,又使我們能夠在其他類中訪問它呢?擴展方法的顯著特征是this其第一個參數(shù)上的 修飾符。這是“魔術(shù)”,可以將其標(biāo)識為編譯器的擴展方法。它修改的參數(shù)的類型(在本例中為IEnumerable)表示將要實現(xiàn)此方法的類或接口。

          (另一方面,IEnumerable接口名稱和Enumerable定義擴展方法的類的名稱 之間的相似性并沒有什么神奇的。這種相似性只是一個任意的樣式選擇。)

          有了這種理解,我們還可以看到sumAccounts上面介紹的功能可以改為如下實現(xiàn):

            public decimal SumAccounts(IEnumerable<Account> myAccounts) {
          return Enumerable.Sum(myAccounts, a => a.Balance);
          }

          我們本可以以這種方式實現(xiàn)它的事實反而引起了一個問題,為什么根本沒有擴展方法? 擴展方法[3]本質(zhì)上是C#編程語言的一種便利,它使您可以將方法“添加”到現(xiàn)有類型,而無需創(chuàng)建新的派生類型,重新編譯或修改原始類型。

          通過using [namespace];在文件頂部包含一條語句,可將擴展方法納入范圍。您需要知道哪個C#名稱空間包含要查找的擴展方法,但是一旦知道要查找的內(nèi)容,就很容易確定。

          當(dāng)C#編譯器在對象的實例上遇到方法調(diào)用,但未找到在引用的對象類上定義的方法時,它將查看范圍內(nèi)的所有擴展方法,以嘗試查找與所需方法匹配的擴展方法。如果找到一個,它將實例引用作為該擴展方法的第一個參數(shù)傳遞,然后其余參數(shù)(如果有)將作為后續(xù)參數(shù)傳遞給擴展方法。(如果C#編譯器在范圍內(nèi)找不到任何相應(yīng)的擴展方法,它將拋出錯誤。)

          擴展方法是C#編譯器中“語法糖”的一個示例,它使我們能夠編寫(通常)更清晰,更可維護(hù)的代碼。更清楚的是,如果您知道它們的用法。否則,可能會有些混亂,尤其是在開始時。

          盡管使用擴展方法當(dāng)然具有優(yōu)勢,但它們可能會引起問題,并且對于那些不了解它們或不正確理解它們的開發(fā)人員,C#編程幫助會大聲疾呼。當(dāng)在線查看代碼示例或任何其他預(yù)先編寫的代碼時,尤其如此。當(dāng)此類代碼產(chǎn)生編譯器錯誤時(因為它調(diào)用的類顯然沒有定義方法),人們傾向于認(rèn)為該代碼適用于該庫的不同版本,或完全適用于不同的庫,可能會由于“缺少庫”花費大量時間搜索不存在的新版本。

          當(dāng)對象上存在具有相同名稱的方法時,即使熟悉擴展方法的開發(fā)人員仍然偶爾會被捕獲,但是其方法簽名與擴展方法的方法簽名之間存在細(xì)微的差異。尋找錯別字或錯誤可能會浪費很多時間。

          在C#庫中使用擴展方法變得越來越普遍。除LINQ之外,Unity Application Block[4]Web API框架[5]是Microsoft經(jīng)常使用的兩個現(xiàn)代庫的示例,它們也使用擴展方法,并且還有許多其他方法。框架越現(xiàn)代,就越有可能包含擴展方法。

          當(dāng)然,您也可以編寫自己的擴展方法。請意識到,盡管擴展方法看起來像常規(guī)實例方法一樣被調(diào)用,但這實際上只是一種幻想。特別是,您的擴展方法不能引用它們正在擴展的類的私有成員或受保護(hù)成員,因此不能完全替代更傳統(tǒng)的類繼承。

          常見的C#編程錯誤#7:為當(dāng)前任務(wù)使用錯誤的集合類型

          C#提供了大量的各種對象集合,具有以下僅為部分清單:

          Array,ArrayList,BitArray,BitVector32,Dictionary<K,V>,HashTable,HybridDictionary,List,NameValueCollection,OrderedDictionary,Queue, Queue,SortedList,Stack, Stack,StringCollection,StringDictionary。

          盡管在某些情況下,太多的選擇和不足的選擇一樣糟糕,但對于集合對象卻并非如此。可用的選項數(shù)量肯定可以使您受益。預(yù)先花一些時間進(jìn)行研究,然后為您的目的選擇最佳的收集類型。這可能會導(dǎo)致更好的性能和更少的錯誤空間。

          如果有一種收集類型專門針對您擁有的元素類型(例如字符串或位),則傾向于首先使用該元素。當(dāng)針對特定類型的元素時,實現(xiàn)通常會更高效。

          為了利用C#的類型安全性,通常應(yīng)首選使用通用接口而不是非通用接口。泛型接口的元素是您在聲明對象時指定的類型,而非泛型接口的元素則是object類型。使用非泛型接口時,C#編譯器無法對您的代碼進(jìn)行類型檢查。同樣,在處理原始值類型的集合時,使用非泛型集合將導(dǎo)致這些類型的重復(fù) 裝箱/拆箱[6],與適當(dāng)類型的泛型集合相比,可能會對性能產(chǎn)生重大的負(fù)面影響。

          另一個常見的C#問題是編寫您自己的集合對象。但這并不是說它永遠(yuǎn)不合適,但是通過提供.NET提供的廣泛選擇,您可以通過使用或擴展已經(jīng)存在的擴展而不是重新發(fā)明輪子來節(jié)省大量時間。特別是,用于C#和CLI的C5通用集合庫“開箱即用”提供了各種各樣的附加集合,例如持久樹數(shù)據(jù)結(jié)構(gòu),基于堆的優(yōu)先級隊列,哈希索引數(shù)組列表,鏈接列表等等。

          常見的C#編程錯誤#8:忽略釋放資源

          CLR環(huán)境使用垃圾回收器,因此您無需顯式釋放為任何對象創(chuàng)建的內(nèi)存。實際上,您不能。沒有C ++ delete運算符或free()這樣的函數(shù)。但這并不意味著您在使用完所有對象后就可以忘記所有對象。許多類型的對象封裝了其他類型的系統(tǒng)資源(例如,磁盤文件,數(shù)據(jù)庫連接,網(wǎng)絡(luò)套接字等)。保持這些資源開放狀態(tài)會迅速耗盡系統(tǒng)資源的總數(shù),從而降低性能并最終導(dǎo)致程序錯誤。

          盡管可以在任何C#類上定義析構(gòu)函數(shù)方法,但析構(gòu)函數(shù)(在C#中也稱為終結(jié)器)存在的問題是,您不確定是否會調(diào)用它們。它們在將來的不確定時間內(nèi)被垃圾收集器調(diào)用(在單獨的線程上,這可能會導(dǎo)致其他問題)。嘗試通過強制使用垃圾回收來克服這些限制 GC.Collect()不是C#最佳實踐[7],因為這將在線程收集所有符合收集條件的對象時在未知時間內(nèi)阻塞線程。

          這并不是說終結(jié)器沒有很好的用途,但是以確定性方式釋放資源并不是其中之一。相反,當(dāng)您在文件,網(wǎng)絡(luò)或數(shù)據(jù)庫連接上進(jìn)行操作時,您希望在完成使用后立即顯式釋放基礎(chǔ)資源。

          在幾乎所有環(huán)境中,[8]資源泄漏都是一個問題。但是,C#提供了一種健壯且易于使用的機制,如果使用該機制,則使泄漏的情況更加罕見。.NET框架定義了IDisposable僅由Dispose()方法組成的接口 。任何實現(xiàn)的對象都IDisposable希望在對象的使用者完成對它的操作后才調(diào)用該方法。這導(dǎo)致顯式,確定性的資源釋放。

          如果要在單個代碼塊的上下文中創(chuàng)建和處理對象,則忘記調(diào)用基本上是不可原諒的 Dispose(),因為C#提供了一條using語句, Dispose()無論代碼塊如何退出(無論它是例外,return陳述式,或是干脆關(guān)閉區(qū)塊)。是的,這與using前面提到的語句相同,該語句用于在文件頂部包含C#名稱空間。它有第二個完全不相關(guān)的目的,許多C#開發(fā)人員都不知道。即,確保Dispose()在退出代碼塊時對對象進(jìn)行調(diào)用:

                using (FileStream myFile = File.OpenRead("foo.txt")) {        myFile.Read(buffer, 0, 100);      }

          通過using 在上面的示例中創(chuàng)建一個塊,您可以確定 myFile.Dispose()在處理完文件后立即調(diào)用該塊,無論是否Read()引發(fā)異常。

          常見的C#編程錯誤#9:回避異常

          C#將其類型安全性強制實施到運行時。這使您能夠比在C ++等語言中更快地查明C#中的許多類型的錯誤,在C#中錯誤的類型轉(zhuǎn)換可能導(dǎo)致將任意值分配給對象的字段。但是,程序員再次可以浪費這一強大功能,從而導(dǎo)致C#問題。之所以陷入這種陷阱,是因為C#提供了兩種不同的處理方式,一種可以引發(fā)異常,而另一種則不能。有些人會回避異常路由,認(rèn)為不必編寫try / catch塊可以節(jié)省一些代碼。

          例如,以下兩種方法可以在C#中執(zhí)行顯式類型轉(zhuǎn)換:

                // METHOD 1:      // Throws an exception if account can't be cast to SavingsAccount      SavingsAccount savingsAccount = (SavingsAccount)account;
          // METHOD 2: // Does NOT throw an exception if account can't be cast to // SavingsAccount; will just set savingsAccount to null instead SavingsAccount savingsAccount = account as SavingsAccount;

          使用方法2可能發(fā)生的最明顯的錯誤是無法檢查返回值。這可能會導(dǎo)致最終的NullReferenceException,該異常可能會在更晚的時間浮出水面,從而更加難以找到問題的根源。相反,方法1會立即拋出一個 InvalidCastException問題,使問題的根源更加明顯。而且,即使您記得在方法2中檢查過返回值,如果發(fā)現(xiàn)它為空,您將怎么辦?您編寫的方法是否適合報告錯誤?如果強制轉(zhuǎn)換失敗,您還可以嘗試其他方法嗎?如果不是,那么拋出異常是正確的事,因此您最好讓它盡可能地靠近問題的根源。

          這是其他兩個常見方法對的兩個示例,其中一個拋出異常而另一個不拋出異常:

                int.Parse();     // throws exception if argument can’t be parsed      int.TryParse();  // returns a bool to denote whether parse succeeded
          IEnumerable.First(); // throws exception if sequence is empty IEnumerable.FirstOrDefault(); // returns null/default value if sequence is empty

          一些C#開發(fā)人員是如此“異常不利”,以至于他們自動認(rèn)為不拋出異常的方法是更好的。盡管在某些特定情況下這可能是正確的,但作為概括,它根本不正確。作為一個特定的示例,如果您有替代的合法(例如,默認(rèn))操作要發(fā)生,那么將產(chǎn)生異常,那么非異常方法可能是一個合法的選擇。在這種情況下,寫這樣的東西確實更好:

                if (int.TryParse(myString, out myInt)) {        // use myInt      } else {        // use default value      }

          代替:

                try {        myInt = int.Parse(myString);        // use myInt      } catch (FormatException) {        // use default value      }

          但是,認(rèn)為TryParse必然是“更好”的方法是不正確的。有時候是這種情況,有時候不是。這就是為什么有兩種方法可以做到這一點。在您所處的環(huán)境中使用正確的方法,請記住,作為開發(fā)人員,異常肯定可以成為您的朋友。

          常見的C#編程錯誤#10:允許編譯器警告累積

          盡管此問題絕對不是C#特有的,但由于放棄了C#編譯器提供的嚴(yán)格類型檢查的優(yōu)點,因此在C#編程中尤為突出。

          產(chǎn)生警告是有原因的。盡管所有C#編譯器錯誤都表明您的代碼有缺陷,但許多警告也是如此。兩者的區(qū)別在于,在出現(xiàn)警告的情況下,編譯器在發(fā)出代碼所表示的指令時沒有問題。即使這樣,它也會發(fā)現(xiàn)您的代碼有些混亂,并且您的代碼有可能無法準(zhǔn)確反映您的意圖。

          就本C#編程教程而言,一個常見的簡單示例是,當(dāng)您修改算法以消除對正在使用的變量的使用時,卻忘記了刪除變量聲明。該程序?qū)⑼昝肋\行,但編譯器將標(biāo)記無用的變量聲明。程序運行完美的事實導(dǎo)致程序員忽略了修復(fù)警告原因的方法。此外,編碼人員還利用了Visual Studio功能,該功能使他們可以輕松地將警告隱藏在“錯誤列表”窗口中,從而使他們只能專注于錯誤。很快就出現(xiàn)了數(shù)十種警告,所有這些警告都被幸福地忽略了(或更糟的是隱藏了)。

          但是,如果您遲早忽略這種類型的警告,則類似這樣的內(nèi)容很可能會在您的代碼中找到:

                class Account {
          int myId; int Id; // compiler warned you about this, but you didn’t listen!
          // Constructor Account(int id) { this.myId = Id; // OOPS! }
          }

          而且,以Intellisense允許我們編寫代碼的速度,此錯誤并不像看起來那樣不可能。現(xiàn)在,您的程序中出現(xiàn)了嚴(yán)重錯誤(盡管出于已經(jīng)說明的原因,編譯器僅將其標(biāo)記為警告),并且根據(jù)程序的復(fù)雜程度,您可能會浪費大量時間來跟蹤該程序。如果您首先注意了此警告,則只需五秒鐘即可解決此問題。

          記住,如果您正在偵聽,C Sharp編譯器會為您提供有關(guān)代碼健壯性的許多有用信息。不要忽略警告。通常,它們只需要花費幾秒鐘的時間進(jìn)行修復(fù),而在發(fā)生新問題時修復(fù)它們可以節(jié)省您的時間。訓(xùn)練自己,使Visual Studio“錯誤列表”窗口顯示“ 0錯誤,0警告”,以便所有警告使您感到不舒服,無法立即解決它們。

          當(dāng)然,每個規(guī)則都有例外。因此,有時您的代碼對編譯器來說似乎有些混亂,即使這正是您的預(yù)期。在極少數(shù)情況下,請#pragma warning disable [warning id]僅在周圍使用觸發(fā)警告的代碼,并僅使用其觸發(fā)的警告ID。這將取消該警告,并且僅禁止該警告,因此您仍然可以保持警惕以防出現(xiàn)新的警告。

          結(jié)論

          C#是一種功能強大且靈活的語言,具有許多可以極大地提高生產(chǎn)率的機制和范例。但是,就像使用任何軟件工具或語言一樣,對其功能的有限了解有時可能更多的是障礙而不是收益,可能會導(dǎo)致生產(chǎn)環(huán)境代碼的問題頻發(fā)。為此,我們需要更多的了解C#語言中那些常見的錯誤,并不斷的持續(xù)優(yōu)化,確保每一行代碼都處于可控的狀態(tài)。

          在你的日常開發(fā)過程中,你是否也曾經(jīng)遇到過這些常見錯誤?趕緊跟你身邊的伙伴一起分享吧~

          References

          [1] 語言: http://msdn.microsoft.com/en-us/library/bb308959.aspx
          [2] 語言集成查詢: http://msdn.microsoft.com/en-us/library/bb308959.aspx
          [3] 擴展方法: http://msdn.microsoft.com/en-us/library/bb383977.aspx
          [4] Unity Application Block: http://msdn.microsoft.com/en-us/library/ff648512.aspx
          [5] Web API框架: http://msdn.microsoft.com/en-us/library/hh833994%28v=vs.108%29.aspx
          [6] 裝箱/拆箱: http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx
          [7] C#最佳實踐: https://orcharddojo.net/orchard-resources/Library/DevelopmentGuidelines/BestPractices/CSharp
          [8] 所有環(huán)境中,: https://www.toptal.com/c-sharp/how-to-make-an-android-and-ios-app-in-c-on-a-mac




















































          回復(fù) 【關(guān)閉】學(xué)關(guān)
          回復(fù) 【實戰(zhàn)】獲取20套實戰(zhàn)源碼
          回復(fù) 【被刪】學(xué)
          回復(fù) 【訪客】學(xué)
          回復(fù) 【小程序】學(xué)獲取15套【入門+實戰(zhàn)+賺錢】小程序源碼
          回復(fù) 【python】學(xué)微獲取全套0基礎(chǔ)Python知識手冊
          回復(fù) 【2019】獲取2019 .NET 開發(fā)者峰會資料PPT
          回復(fù) 【加群】加入dotnet微信交流群

          又來一個神奇的網(wǎng)站!


          人人影視字幕組涼了,這款美劇APP不能錯過!


          瀏覽 24
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美一级毛片免费高清老鸭窝 | 亚洲免费看黄网站 | www.日逼网站 | 天天射天天日天天操 | 操人视频网站 |