狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

C#幾個經常犯錯誤匯總

admin
2024年6月4日 17:43 本文熱度 778
轉自:指尖流淌
cnblogs.com/zhijianliutang/archive/2012/03/20/2407688.html

     在我們平常編程中,時間久了有時候會形成一種習慣性的思維方式,形成固有的編程風格,但是有些地方是需要斟酌的,即使是一個很小的錯誤也可能會導致昂貴的代價,要學會善于總結,從錯誤中汲取教訓,盡量不再犯同樣錯誤,注重編程之美,代碼的優雅,總結幾個平常經常犯的錯誤。

1、在C#編程中,字符型類型是最容易處理出錯的地方,代價是非常昂貴,在.Net Framwork中,字符串是一個相當特別的引用類型,string本省就是一個不可繼承的密封類,但是它具有了值類型所應用的特點,但是它在CLR中內存還是保存于托管堆之上,也就是說,當我們每次定義一個字符串類型的時候,就在堆內存中開辟一端內存,而當我們字符串被修改之后,它會創建一個新的內存,注意這里的內存是不連續的,而是通過修改棧內地址引用而拼湊字符串,不會改變源字符串在內存中的地址,所以有些程序員總是喜歡使用這樣的方法格式化字符串:

string  SelectText="select * from "+TableName+" where UserName='"+Name+"'";

上述代碼,使用了字符串拼湊的方法,因為使用了多重串聯,因此會在內存中創建兩個不必要的字符串垃圾副本。

其實在C#中,已經為我們提供了StringBuilder和String.Fromat來解決此問題,雖然他們可以實現同樣的功能,但是他們有質的變化,StringBuilder在內存中開辟的是一段連續內存,當增加新字符串時候,它會在棧中指向的同一個堆內存中連續存放字符,這就形成了性能的提升。所以我們將上面代碼改成:

string SelectText=string.Format("select  *  from {0} where UserName={1}",TableName,Name);

2、大多數開發人員都不知道內置的驗證數據類型的方法,如System.Int32,因此很多人都是自己實現的,其實這是不妥的,因為這些基本類型中都存在自己固有的類型驗證方法,下面這個就是自己實現驗證的一個字符串是否是數值的代碼:

public bool CheckIfNumeric(string value)

{

  bool IsNumeric=true;

  try

  {

    int i=Convert.ToInt32(value);

  }

  catch(FormatException excepiton)

  {

    IsNumeric=false;

  }

  return IsNumeric;

}

雖然使用了try catch語句,這不是最佳的做法,更好的方法是下面使用Int.TryParse;

int output=0;

bool IsNumeric=int.TryParse(value,out output);

int.TryParse是更快、更簡潔的方法。

3、自己利用IDisposable接口手動釋放內存

在.NET Framework中,對象的處理和使用一樣重要,理想的方法是在使用完對象的時候,在類中實現IDisposable接口中的dispose方法進行內存的釋放,當然在.Net本身提供的垃圾回收機制(GC)中就提供了這樣的功能,在我們實例化類對象時,在類本身的析構函數中會調用dispose方法,GC在各級內存堆滿的情況下,自動檢查對象使用情況,去相應的釋放內存,但是運行在非托管平臺上的方法,需要我們自己手動釋放內存,比如我們常見的SqlConnection對象,也就有了下面的創建、使用和處理方法:

public void  DALOneMethod()

{

  SqlConnection  connection=null;

  try

  {

    connection =new SqlConnection("。。。。。。。。。。。");

    connection.Open();

    //sqlcommand。。run

  }

  catch(Exception exception)

  {

    // manager exception

  }

  finally

  {

    connection.Close();

    connection.Disopse();

  }

}

上述代碼是大部分程序員會出現的代碼,乍看沒啥問題,連接處理在最后一個代碼中被明確調用,但是如果發生了一個異常,catch代碼塊就被執行,然后再執行最后一個代碼塊處理連接,因此在最后一個代碼塊執行之前,連接將一直留在內存中,大部分我們會在此處記錄錯誤,一般涉及到IO操作,如果延時時間比較長的話,這個連接將在內存時間長時間停留。我們一個原則就是當對象不再使用的時候我們里面釋放資源。

我們采用程序邏輯域來處理這個問題會更好:

public void  DALOneMethod()

{

  using(SqlConnction  connection=new SqlConnection("。。。。。。。"))

  {

    connction.Open();

    // do SUAD

  }

}

當使用using代碼快時,對象上的dispose()方法將在執行推出邏輯域的時候調用,這樣就保證了SqlConnection的資源處理被盡早釋放,當然這個方法也適用于實現IDisposable接口的類,當時個人不推薦這樣做,在非常有把握的情況下可以手動釋放,但是沒把握還是叫給.net系統釋放,因為本身類的析構函數就迪終飧齜椒ǎ蔽頤親約褐匭春螅炊岬賈孿低澄笠暈闋約憾ㄒ辶朔椒ǎ瞥偈頭拋試矗行巳た梢匝芯肯翯C運行本質,假如能在第一代被釋放的內存,如果我們重寫dispose方法反而推遲到第二代內存堆中釋放,顯然是不可取的。

4、學會合理的管理公共變量,我們在系統中經常會濫用公共變量,沒有做到合適的封裝好。

static void Main(string[] args)

{

  MyAccount account=new MyAccount();

  //這地方不能隨便的調用account里面的字段進行更改,但是缺改了

  account.AccountNumber="ddddddddd";

  Console.ReadKey();

}


public class MyAccount

{

  public string AccountNumber;

  public MyAcctount()

  {

    AccountNumber="ssssssssssssss";

  }

}

   在上面的MyAccount類中生命了一個AccountNumber公共變量,理想情況下,AccountNumber應該是只讀的,不能讓外界修改,但是這里MyAccount類卻沒有對它做任何控制。

聲明公共做法應該是使用屬性,如:

public class MyAccount

{

  private stirng _accountNumber;

  public string AccountNumber

  {

    get { return _accountNumber; }

  }

  public MyAccount()

  {

    _accountNumber="dddddddd";

  }

}

這里我們封裝了AccountNumber公共變量,它變成了只讀,不能由調用者類進行修改。

5、嵌套的異常處理,有的開發人員喜歡在方法末尾加上處理的嵌套方法,如:

public class NestedExceptionHandling

{

  public void MainMethod()

  {

    try

    {

      //some implementation

      ChildMethod1();

    }

    catch (Exception exception)

    {

      //Handle exception

    }

  }


  private void ChildMethod1()

  {

    try

    {

      //some implementation

      ChildMethod2();

    }

    catch (Exception exception)

    {

      //Handle exception

      throw;

    }

  }


  private void ChildMethod2()

  {

    try

    {

      //some implementation

    }

    catch (Exception exception)

    {

      //Handle exception

      throw;

    }

  }

}

如果相同的異常被處理多次,性能開銷將會增加。

我們的解決方法是讓異常處理方法獨立開來,如:

public class NestedExceptionHandling

{

  public void MainMethod()

  {

    try

    {

      //some implementation

      ChildMethod1();

    }

    catch(Exception exception)

    {

      //Handle exception

    }

  }


  private void ChildMethod1()

  {

    //some implementation

    ChildMethod2();

  }


  private void ChildMethod2()

  {

    //some implementation

  }

}

6、大數據量上使用Dataset和DataReader混用,當單表數據量很大的情況,使用DataSet是一種很不明智的選擇,應為DataSet是以DataTable內存形式存放數據量,一次性將數據拖入內存,當數據很大的情況下,這種方式是很吃內存的,相比DataSer,DataReader就顯得優雅很多,它是每次讀取一條數據,然后輪詢調用機制,但是也有它的弊端,就是相對長連接,但是對內存消耗而言這是有利的,當然DataSet在大部分應用場景下也是有自己的優點,充分解耦、一次性操作、領域模型操作等方面,兩者分情況分場景而用,這里只是稍微提提,根據場景分析區別。

內容更正

原篇文章不動,感謝園友的點評,更正幾處內容:

1、第一條String類型內存消耗問題,舉的例子不到位,在字符串數量少的時候性能沒有影響的,但就在.net Framwork平臺運行,分析應該就是此原理了。

現將老趙分析的結論歸結如下:

     <1>對于字符串數量比較少的情況(從數據上來看大約是5-6個),StringBuilder的性能并不比普通連接操作來的快。因此,在任何地方都使用StringBuilder是不恰當的做法。    

參照:http://blog.zhaojie.me/2009/11/string-concat-perf-1-benchmark.html

另附性能比較源碼同樣出自老趙博文,有興趣的園友可自行比較測試:http://www.cnblogs.com/zhijianliutang/archive/2011/12/17/2291323.html

2、類對象在使用完對象后并不是通過析構函數調用Dispose方法實現垃圾回收,Dispose是.net類庫提供的一個釋放內存的方法,供開發人員自行調用,它是通過Finalizer是供GC調用。

關于其他SQL注入、屬性公開知否妥當、自行調用Dispose方法釋放內存是否會推遲釋放等觀點都是分應用場景而言,算作拋磚引玉吧,非絕對。最后謝園友們指點。


- EOF -


該文章在 2024/6/5 22:35:45 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved