<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#代碼的技巧

          共 10668字,需瀏覽 22分鐘

           ·

          2020-11-28 18:32

          寫好C#代碼的技巧

          編者導(dǎo)語


          本文來自https://www.pluralsight.com,作者Afzaal Ahmad Zeeshan。

          原文包含以下三篇文章:

          《編寫更好的C#代碼簡介》https://www.pluralsight.com/guides/introduction-to-writing-better-csharp-code

          《編寫更好的C#代碼的技巧》https://www.pluralsight.com/guides/tips-for-writing-better-c-code

          《有關(guān)編寫更好的C#代碼的更多技巧》https://www.pluralsight.com/guides/more-tips-for-writing-better-csharp-code

          雖然本文僅介紹了C#6.0語言特性,而現(xiàn)在最新的C#已經(jīng)到了9.0,但這些內(nèi)容已經(jīng)仍然常讀常新。

          一、簡介

          C#已從C#5更改為C#6,為使項(xiàng)目更具可讀性,基于最佳標(biāo)準(zhǔn)的實(shí)踐也得到了發(fā)展。

          本指南系列的目的是幫助您為在團(tuán)隊(duì)環(huán)境中運(yùn)行的C#項(xiàng)目和.NET Framework應(yīng)用程序編寫更簡潔的代碼。在團(tuán)隊(duì)環(huán)境下,編寫好的代碼對開發(fā)人員可能更容易,因?yàn)榫帉懙拇a將由團(tuán)隊(duì)中其他開發(fā)人員使用,管理和更新,而代碼質(zhì)量往往取決于您個(gè)人團(tuán)隊(duì)的“哲學(xué)”和開發(fā)人員的編碼實(shí)踐。

          在這種情況下,最好的方法是遵循編碼團(tuán)隊(duì)的準(zhǔn)則,并為應(yīng)用程序項(xiàng)目中的C#程序添加設(shè)計(jì)和風(fēng)格,以使它們對讀者更好。請注意,C#編譯器并不關(guān)心您放入代碼中的風(fēng)格。但我們以一種使C#應(yīng)用程序?qū)ψx者來說看起來更簡單,更清潔,將更容易的方式更深入地進(jìn)行編程,同時(shí)保持代碼開發(fā)的性能和效率。

          在閱讀本指南之前,您應(yīng)該了解以下幾點(diǎn):

          1.第6版對C#的改進(jìn)2..NET框架中的LINQ3.TaskC#中的異步編程和對象4.使用C#進(jìn)行的不安全編程,使您無法正常的使用內(nèi)存管理

          不專注于性能

          應(yīng)該注意的是,我不會(huì)談?wù)摳淖兂绦蛐阅埽岣咝驶驕p少程序運(yùn)行所花費(fèi)的時(shí)間。通過編寫簡潔的C#代碼,您可以在幾秒鐘內(nèi)提高程序性能,但是以下技巧并不能保證您的代碼性能更好。

          為什么要編寫整潔的代碼?

          您編寫代碼,編譯器編譯時(shí)沒有警告也沒有錯(cuò)誤,代碼很好。但是,如果其他人想讀出該代碼怎么辦?如果有人后來需要為您或您所在的公司升級代碼,該怎么辦?看下面的代碼:

          public static void Main(string[] args) {  int x = 0;  x = Console.Read();
          Console.WriteLine(x * 1.5);}

          該程序運(yùn)行良好,系統(tǒng)中沒有錯(cuò)誤,應(yīng)用程序也可以正常工作。但是您能告訴我該程序在現(xiàn)實(shí)生活中做什么嗎?以下是可以做出的一些假設(shè):

          1.它只是乘以價(jià)值2.就像獎(jiǎng)金一樣,它正在增加價(jià)值3.是個(gè)人銀行存款總額的利率4.等等。

          哪一個(gè)是真實(shí)的?沒有人會(huì)知道。在這種情況下,最好編寫出良好的代碼,并記住遵循編程的基礎(chǔ)。看下面的代碼:

          public static void Main(string[] args) {  int salary = 0;  salary = Console.Read();
          Console.WriteLine(salary * 1.5);}

          這比以前的代碼有意義嗎?我們可以很容易地說這個(gè)代碼將增加薪水的價(jià)值。請注意,僅通過改進(jìn)代碼,我們就能確保其他人可以比以前更快地理解它。

          在本指南中,我不會(huì)向您展示如何遵循最佳原則。相反,我將以您已有的知識為基礎(chǔ),并教您如何充分利用C#程序。我將重點(diǎn)介紹如何在應(yīng)用程序中編寫良好的C#邏輯,因此您將看到通過以這種方式和結(jié)構(gòu)編寫程序,可以從應(yīng)用程序中獲得很多好處。

          因此,讓我們開始吧。

          對象初始化

          C#是一種面向?qū)ο蟮木幊陶Z言。如果對象本身沒有分塊,那么寫一組提示有什么好處?本節(jié)將重點(diǎn)介紹在前進(jìn)并new Object()在應(yīng)用程序中編寫代碼之前應(yīng)考慮的事項(xiàng)。您必須了解如何創(chuàng)建C#類以及事物如何協(xié)作以在系統(tǒng)中啟動(dòng)一個(gè)小程序。

          例如,看下面的代碼:

          class Person {  public int ID { get; set; }  public string Name { get; set; }  public DateTime DateOfBirth { get; set; }  public bool Gender { get; set; }}

          您可能想要?jiǎng)?chuàng)建默認(rèn)情況下設(shè)置值的程序,或者讓它們來自模型或諸如此源代碼的任何其他面向數(shù)據(jù)庫的數(shù)據(jù)源,這些程序簡化了在對象時(shí)輸入默認(rèn)值的方式正在創(chuàng)建。

          var person = new Person { ID = 1, Name = "Afzaal Ahmad Zeeshan", DateOfBirth = new DateTime(1995, 08, 29), Gender = true };

          相反,請嘗試通過以下方式編寫相同的代碼:

          var person = new Person();person.ID = 1;person.Name = "Afzaal Ahmad Zeeshan";// So on.

          這里的代碼沒有明顯的性能改進(jìn),但是可以真正提高代碼的可讀性。如果您喜歡縮進(jìn),請?jiān)谶@里查看:


          var person = new Person{  ID = 1,  Name = "Afzaal Ahmad Zeeshan",  DateOfBirth = new DateTime(1995, 08, 29),  Gender = true};

          這也有縮進(jìn),但是它為您的C#代碼的可讀性添加了更多的說明。盡管前面的代碼可以實(shí)現(xiàn)相同的功能,但是建議的代碼可以使代碼更易讀和簡潔。

          二、技巧

          空檢查

          NullReferenceException當(dāng)缺少初始化的對象再次拋出異常時(shí),您是否曾經(jīng)對感到惱火?在程序中進(jìn)行空檢查有很多好處,不僅可以提高可讀性,而且可以確保程序不會(huì)由于內(nèi)存問題而終止(例如,內(nèi)存中不存在變量時(shí))。這些可能與程序的安全性以及團(tuán)隊(duì)具有的良好UI和UX準(zhǔn)則相抵觸。大多數(shù)情況下,由于以下原因會(huì)引發(fā)空異常:

          string name = null;
          Console.WriteLine(name);

          在大多數(shù)情況下,除非您解決此問題,否則編譯器本身不會(huì)繼續(xù)運(yùn)行,但是如果您設(shè)法以某種方式誘使編譯器認(rèn)為變量具有值,但在運(yùn)行時(shí)沒有變量,則會(huì)出現(xiàn)空引用異常。為了克服這個(gè)問題,您可以執(zhí)行以下操作:


          string name = null;
          // Try to enter the value, from somewhereif(name != null) { Console.WriteLine(name);}

          此安全檢查將確保在調(diào)用此變量時(shí)該值可用。否則,它將影響您代碼的路徑。但是,在C#6中,還有另一種方法可以克服此錯(cuò)誤??紤]以下情形:建立數(shù)據(jù)庫,建立數(shù)據(jù)表,找到您的人員但找不到他們的就業(yè)詳細(xì)信息。你能找到他們工作的公司嗎?

          var company = DbHelper.PeopleTable.Find(x => x.id == id).FirstOrDefault().EmploymentHistory.CompanyName; // Error

          如果您這樣做,將會(huì)出現(xiàn)錯(cuò)誤,因?yàn)槲覀冎荒茉谶@些值的列表中進(jìn)行簡單幾步的對象篩選。然后我們將碰到一個(gè)空值,一切都丟失了。C#6提出了一種克服這些情況的新方法,方法是在值和字段可以為null的后面使用安全的導(dǎo)航運(yùn)算符。?.。像這樣:

          var company = DbHelper?.PeopleTable?.Find(x => x.id == id)?.FirstOrDefault()?.EmploymentHistory?.CompanyName; // Works

          如果前一個(gè)不為null,則此代碼僅檢查下一個(gè)值。如果先前的值為null,它將返回null并將null保存為的值company,而不是引發(fā)錯(cuò)誤。將檢查留給框架本身可以很方便,但是,盡管如此,您仍然必須在最后檢查其余值是否為null。

          var company = DbHelper.PeopleTable?.Find(x => x.id == id)?.FirstOrDefault()?.EmploymentHistory?.CompanyName;
          if(company != null) { // Final process}

          但是您明白了這一點(diǎn),而不是編寫代碼并檢查所有內(nèi)容是否為空,而是可以執(zhí)行簡單的檢查并執(zhí)行程序中想要的操作和邏輯。否則,將需要try...catch包裝器或多個(gè)if...else塊來控制程序在系統(tǒng)中的導(dǎo)航方式。

          異步編程模式

          如果您正在使用C#5進(jìn)行編程,那么您已經(jīng)在使用async / await關(guān)鍵字為您的應(yīng)用程序帶來改進(jìn)。如果不是這種情況,那么我建議您在應(yīng)用程序的源代碼中使用異步編程模式。這不僅可以提高對程序的響應(yīng)速度,還可以提高應(yīng)用程序的可讀性。在源代碼中具有異步模式的一些好處是:

          1.代碼路徑開始變得更加有意義。如果有一個(gè)進(jìn)程在后臺開始運(yùn)行,那么程序員可以了解程序應(yīng)該在哪里。2.應(yīng)用程序掛起問題將消失。大多數(shù)與應(yīng)用程序阻塞相關(guān)的問題直接來自代碼。當(dāng)UI線程無法更新UI時(shí),用戶會(huì)認(rèn)為該應(yīng)用程序正在掛起并且沒有響應(yīng),而事實(shí)并非如此。異步方法確實(shí)可以幫上大忙。3.基于Windows運(yùn)行時(shí)的應(yīng)用程序完全基于此方法。您將(并且必須是!)在您的Windows Runtime應(yīng)用程序中使用這種方法來解決諸如掛起應(yīng)用程序或不良的編程習(xí)慣之類的問題。

          自從線程化以來,代碼執(zhí)行的并行化就已經(jīng)存在。異步已經(jīng)成為程序和應(yīng)用程序的重要組成部分,因此您更應(yīng)該考慮使用它。

          C#字符串構(gòu)建

          字符串是當(dāng)今應(yīng)用程序的重要組成部分,構(gòu)建字符串可能會(huì)花費(fèi)很多時(shí)間,并且還會(huì)導(dǎo)致應(yīng)用程序性能下降。您可以通過多種方式在C#程序中構(gòu)建字符串。以下是其中幾種方式:

          string str = ""; // Setting it to null would cause additional problems.
          // Way 1str = "Name: " + name + ", Age: " + age;
          // Way 2str = string.Format("Name: {0}, Age: {1}", name, age);
          // Way 3var builder = new StringBuilder();builder.Append("Name: ");builder.Append(name);builder.Append(", Age: ");builder.Append(age);str = builder.ToString();

          請注意,C#中的字符串是不可變的。這意味著,如果您嘗試更新它們的值,則會(huì)重新創(chuàng)建它們,并從內(nèi)存中刪除以前的句柄。這就是為什么方式1看起來是最好的方式,但經(jīng)過進(jìn)一步思考,事實(shí)并非如此。最好的方法是方法3,它使您可以構(gòu)建字符串而不必在內(nèi)存中重新創(chuàng)建對象。同時(shí),C#6引入了一種全新的方式在C#中構(gòu)建字符串,該方式比您以前想象的要好得多。新的

          字符串插值 運(yùn)算符$為您提供了以最佳方式執(zhí)行字符串構(gòu)建的功能。字符串插值如下所示:


          static void Main(string[] args){   // Just arbitrary variables   string name = "";   int age = 0;
          // Our interest string str = $"Name: {name}, Age: {age}";}

          只需一行代碼,編譯器就會(huì)自動(dòng)將其轉(zhuǎn)換為string.Format()版本。為了證明這一點(diǎn),將詳細(xì)說明此C#程序已生成的字節(jié)碼,并向您展示如何自動(dòng)更改語法以讀取字符串格式。

          IL_0000:  nopIL_0001:  ldstr       ""IL_0006:  stloc.0     // nameIL_0007:  ldc.i4.0IL_0008:  stloc.1     // ageIL_0009:  ldstr       "Name: {0}, Age: {1}"IL_000E:  ldloc.0     // nameIL_000F:  ldloc.1     // ageIL_0010:  box         System.Int32IL_0015:  call        System.String.FormatIL_001A:  stloc.2     // strIL_001B:  ret

          可以看出,這顯示了如何將語法更改回我們已經(jīng)看到的語法。有關(guān)IL_0009更多信息,請參見。當(dāng)其他人正在讀取程序時(shí),這可以使您的程序外觀更簡潔,并且如果要構(gòu)建的字符串較小,則可以提高性能。如果字符串較大,請使用StringBuilder。

          三、更多技巧

          遍歷數(shù)據(jù)

          如果不對一組數(shù)據(jù)進(jìn)行循環(huán)和迭代,那么應(yīng)用程序有什么用?在這種情況下,有時(shí)您將不得不查找值,查找節(jié)點(diǎn),查找記錄或?qū)线M(jìn)行任何其他遍歷。在這種情況下,您確實(shí)需要確保編寫干凈的代碼,因?yàn)檫@是性能和可讀性都非常重要且相互關(guān)聯(lián)的領(lǐng)域。

          有了一些經(jīng)驗(yàn),我就克服了編寫用于讀取和遍歷數(shù)據(jù)的錯(cuò)誤代碼的方式。這正是LINQ應(yīng)該加入的地方,LINQ允許您編寫使用最佳.NET框架為用戶和客戶提供最佳編碼體驗(yàn)和最佳體驗(yàn)的程序。

          以前,您可能已經(jīng)做過以下一些事情:

          6// A function to search for peoplePerson FindPerson(int id) {   var people = DbContext.GetPeople(); // Returns List
                 
          foreach (var person in people) { if(person.ID == id) { return person; } }
          // No person found. return null;}
          // Then do thisvar person = FindPerson(123);

          對于任何想接手您代碼的人來說,這都是一段易讀的代碼。但是,使用C#中的LINQ查詢可以使代碼更加簡單和整潔。您可以通過兩種方式執(zhí)行此操作。一個(gè)有點(diǎn)像SQL,另一個(gè)是通過Where在集合上使用該函數(shù)并傳遞我們的要求。

          // A function to search for peoplePerson FindPerson(int id) {   var people = DbContext.GetPeople(); // Returns List
                 
          return (from person in people where person.ID == id select person).ToList().FirstOrDefault();}
          // Then do thisvar person = FindPerson(123);

          該代碼看起來有點(diǎn)像SQL,可以增強(qiáng)代碼的可讀性和性能。該函數(shù)相似,但是,該Where函數(shù)的讀取效果更好,并使所有迭代都針對.NET框架本身,而.NET框架將為應(yīng)用程序提供最佳性能。

          現(xiàn)在,讓我們看看用相同的C#代碼編寫此查詢的另一種方式:

          // A function to search for peoplePerson FindPerson(int id) {   var people = DbContext.GetPeople(); // Returns List
                 
          return people.FirstOrDefault(x => x.ID == id);}
          // Then do thisvar person = FindPerson(123);

          請注意,null如果沒有找到匹配項(xiàng),則返回第一個(gè)代碼。這段代碼也做同樣的事情。唯一的第一個(gè)代碼更糟糕的是它必須對集合本身執(zhí)行迭代。

          該本地變量return person;將允許程序返回控件,但是如果數(shù)據(jù)位于最后一個(gè)位置會(huì)發(fā)生什么呢?此數(shù)據(jù)搜索算法的復(fù)雜度仍為O(n)。

          避免unsafe上下文

          在您必須親自處理內(nèi)存時(shí),C#還支持手動(dòng)內(nèi)存管理。C#中的不安全上下文允許您操作內(nèi)存,執(zhí)行指針?biāo)阈g(shù),在可能無法訪問的內(nèi)存位置讀取和寫入數(shù)據(jù),等等。但是,.NET框架可以做很多事情來克服內(nèi)存問題,延遲和磁盤上其他問題。這也使.NET框架完全無需實(shí)際執(zhí)行任何內(nèi)存管理,.NET框架將為您做到這一點(diǎn)。

          使用不安全的上下文有很多好處,例如,當(dāng)您要圍繞本機(jī)C ++庫編寫包裝器時(shí)。Emgu CV就是這樣一個(gè)示例,您將在其中編寫一些代碼來處理如何管理本機(jī)代碼,并以更簡單的方式來處理內(nèi)存中的錯(cuò)誤。在這種情況下,您可以:

          1.使用指針管理和指針?biāo)阈g(shù)。您不能在此上下文之外的任何地址上執(zhí)行任何操作,這是.NET規(guī)則所處的位置。2.使用內(nèi)存管理來操作內(nèi)存中的對象。3.使用C ++風(fēng)格的編程,這正是C#設(shè)計(jì)的目的。

          這幾乎沒有好處,如果您應(yīng)該在應(yīng)用程序中考慮這一點(diǎn),請明智地考慮。

          關(guān)于Unsafe純屬個(gè)人觀點(diǎn)

          我還想指出,關(guān)于“不安全”的利弊,我所說的一切都是我個(gè)人的看法。我不經(jīng)常在程序中使用unsafe上下文,因?yàn)闆]有理由考慮在應(yīng)用程序中使用上下文。但是,如果您的應(yīng)用程序需要本機(jī)內(nèi)存管理,則可以使用此上下文。

          盡可能使用Lambda表達(dá)式

          Lambda來自函數(shù)式編程領(lǐng)域,在C#中已廣泛使用,從內(nèi)聯(lián)函數(shù)一直到C#6中的getter only屬性。我將展示C#中的兩種用法,它們構(gòu)成的程序,不僅看起來更清爽,而且性能指標(biāo)也更高。

          為此,我將向您顯示該C#代碼的IL。我個(gè)人喜歡在許多領(lǐng)域使用lambda,尤其是當(dāng)我不得不用C#編寫內(nèi)聯(lián)函數(shù)時(shí)。自從可以使用此概念編寫僅用于getter的屬性以來,我一直在使用它們,并且我個(gè)人認(rèn)為它比以前做同一件事的方法更好。

          1.將Lambda用于內(nèi)聯(lián)函數(shù)

          您應(yīng)該知道一些C#編程的示例,使用這種寫法的代碼很多。

          例如在應(yīng)用程序中進(jìn)行事件處理的情況下,對于事件處理,您可以像下面這樣編寫當(dāng)前函數(shù):


          // Without lamdbasmyBtn.Click += Btn_Click;
          public void Btn_Click (object sender, EventArgs e) { // Code to handle the event}
          // With the help of lambdasmyBtn.Click += (sender, e) => { // Code to handle the event. }

          請注意,編譯器將自動(dòng)將對象映射到其類型。這在許多方面都很方便,因?yàn)樗试S您用C#編寫僅與對象一起保留的內(nèi)聯(lián)函數(shù),除非您也想在其他任何地方使用它們。但是,這種處理事件的方法有一個(gè)缺點(diǎn):一旦附加了事件處理程序,便無法刪除它。在C#中可以,-+。

          但是由于我們沒有刪除事件的參考,因此只能使用單獨(dú)的函數(shù)。但是,如果不必刪除處理程序,則應(yīng)始終考慮在程序中使用這種事件處理方式。

          2.將Lambda用于僅Getter的屬性

          在C#中,有一個(gè)使用屬性而不是字段的概念。您可以控制如何設(shè)置值以及如何從字段中捕獲值。將其視為Java編程語言的getter和setter方法的替代方法(或類似方法)。唯一的區(qū)別是您不必在某個(gè)地方分別編寫它們,它們直接寫在字段本身的前面。然后,C#程序編譯器將創(chuàng)建自己的后備字段,用于存儲值。

          基本上,您必須編寫如下這樣的屬性:

          public string Name { get; }

          請注意,這些屬性是恒定的,設(shè)置后就無法更改。它們是在構(gòu)造函數(shù)中設(shè)置的,或者(從C#6開始)在它們的前面設(shè)置。像這樣:

          public string Name { get; } = "Afzaal Ahmad Zeeshan";

          但是,由于我們已經(jīng)知道這是一個(gè)常量字段,您不能修改它,那么為什么不創(chuàng)建一個(gè)簡單的常量屬性呢?事情變得有些棘手。甚至一個(gè)屬性也必須由字段來備份。在這種情況下,這將為我們解決問題:

          public string Name => "Afzaal Ahmad Zeeshan";

          這等效于編寫以下內(nèi)容:

          public string Name { get { return "Afzaal Ahmad Zeeshan"; } }

          但是由于編譯期將getter字段轉(zhuǎn)換為常量字段,并且在必須調(diào)用此屬性的時(shí)候才會(huì)在程序中使用該字段,因此性能要好得多。

          最后的話

          本指南系列的目的是使您了解一些使程序更易于閱讀和更好執(zhí)行的方法。C#編譯器本身會(huì)盡最大努力提高代碼的質(zhì)量和效率,而這程序員帶來便利,同時(shí)也將使程序更好地工作。

          除了上面提到的方法,還有許多其他提高可讀性的方法,其中許多方法適合公司團(tuán)隊(duì)協(xié)作的形式編寫程序,因?yàn)榇蠖鄶?shù)團(tuán)隊(duì)往往都要求程序員遵循自己的編程方法和方式。







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

          副業(yè)剛需,沒有人能拒絕這個(gè)網(wǎng)站!


          微信錢包“免費(fèi)提現(xiàn)”的方法來了!



          瀏覽 48
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  天堂a 中文在线 | av毛片网站 | 欧美变态性爱一区二区三区 | 欧美乱伦精品 | 天天日天天干天天拍 |