在我們平常編程中
時間久了有時候會形成一種習慣性的思維方式
形成固有的編程風格
但是有些地方是需要斟酌的
即使是一個很小的錯誤也可能會導致昂貴的代價
要學會善於總結
從錯誤中汲取教訓
盡量不再犯同樣錯誤
注重編程之美
代碼的優雅
總結幾個平常經常犯的錯誤
在C#編程中
字符型類型是最容易處理出錯的地方
代價是非常昂貴
在
Net Framwork中
字符串是一個相當特別的引用類型
string本省就是一個不可繼承的密封類
但是它具有了值類型所應用的特點
但是它在CLR中內存還是保存於托管堆之上
也就是說
當我們每次定義一個字符串類型的時候
就在堆內存中開辟一端內存
而當我們字符串被修改之後
它會創建一個新的內存
注意這裡的內存是不連續的
而是通過修改棧內地址引用而拼湊字符串
不會改變源字符串在內存中的地址
所以有些程序員總是喜歡使用這樣的方法格式化字符串
string SelectText=
select * from
+TableName+
where UserName=
+Name+
;
上述代碼
使用了字符串拼湊的方法
因為使用了多重串聯
因此會在內存中創建兩個不必要的字符串垃圾副本
其實在C#中
已經為我們提供了StringBuilder和String
Fromat來解決此問題
雖然他們可以實現同樣的功能
但是他們有質的變化
StringBuilder在內存中開辟的是一段連續內存
當增加新字符串時候
它會在棧中指向的同一個堆內存中連續存放字符
這就形成了性能的提升
所以我們將上面代碼改成
string SelectText=string
Format(
select * from {
} where UserName={
}
TableName
Name)
大多數開發人員都不知道內置的驗證數據類型的方法
如System
Int
因此很多人都是自己實現的
其實這是不妥的
因為這些基本類型中都存在自己固有的類型驗證方法
下面這個就是自己實現驗證的一個字符串是否是數值的代碼
public bool CheckIfNumeric(string value)
{
bool IsNumeric=true;
try
{
int i=ConvertToInt(value);
}
catch(FormatException excepiton)
{
IsNumeric=false;
}
return IsNumeric;
}
雖然使用了try catch語句這不是最佳的做法更好的方法是下面使用IntTryParse
int output=;
bool IsNumeric=intTryParse(valueout output);
intTryParse是更快更簡潔的方法
自己利用IDisposable接口手動釋放內存
在NET Framework中對象的處理和使用一樣重要理想的方法是在使用完對象的時候在類中實現IDisposable接口中的dispose方法進行內存的釋放當然在Net本身提供的垃圾回收機制(GC)中就提供了這樣的功能在我們實例化類對象時在類本身的析構函數中會調用dispose方法GC在各級內存堆滿的情況下自動檢查對象使用情況去相應的釋放內存但是運行在非托管平台上的方法需要我們自己手動釋放內存比如我們常見的SqlConnection對象也就有了下面的創建使用和處理方法
public void DALOneMethod()
{
SqlConnection connection=null;
try
{
connection =new SqlConnection();
connectionOpen();
//sqlcommandrun
}
catch(Exception exception)
{
// manager exception
}
finally
{
connectionClose();
connectionDisopse();
}
}
上述代碼是大部分程序員會出現的代碼乍看沒啥問題連接處理在最後一個代碼中被明確調用但是如果發生了一個異常catch代碼塊就被執行然後再執行最後一個代碼塊處理連接因此在最後一個代碼塊執行之前連接將一直留在內存中大部分我們會在此處記錄錯誤一般涉及到IO操作如果延時時間比較長的話這個連接將在內存時間長時間停留我們一個原則就是當對象不再使用的時候我們裡面釋放資源
我們采用程序邏輯域來處理這個問題會更好
public void DALOneMethod()
{
using(SqlConnction connection=new SqlConnection())
{
connctionOpen()
// do SUAD
}
}
當使用using代碼快時對象上的dispose()方法將在執行推出邏輯域的時候調用這樣就保證了SqlConnection的資源處理被盡早釋放當然這個方法也適用於實現IDisposable接口的類當時個人不推薦這樣做在非常有把握的情況下可以手動釋放但是沒把握還是叫給net系統釋放因為本身類的析構函數就實現這個方法當我們自己重寫後反而會導致系統誤以為你自己定義了方法而推遲釋放資源有興趣可以研究下GC運行本質假如能在第一代被釋放的內存如果我們重寫dispose方法反而推遲到第二代內存堆中釋放顯然是不可取的
學會合理的管理公共變量我們在系統中經常會濫用公共變量沒有做到合適的封裝好
static void Main(string[] args)
{
MyAccount account=new MyAccount();
//這地方不能隨便的調用account裡面的字段進行更改但是缺改了
accountAccountNumber=ddddddddd;
ConsoleReadKey();
}
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公共變量它變成了只讀不能由調用者類進行修改
嵌套的異常處理有的開發人員喜歡在方法末尾加上處理的嵌套方法如
public class NestedExceptionHandling
{
public void MainMethod()
{
try
{
//some implementation
ChildMethod();
}
catch (Exception exception)
{
//Handle exception
}
}
private void ChildMethod()
{
try
{
//some implementation
ChildMethod();
}
catch (Exception exception)
{
//Handle exception
throw;
}
}
private void ChildMethod()
{
try
{
//some implementation
}
catch (Exception exception)
{
//Handle exception
throw;
}
}
}
如果相同的異常被處理多次性能開銷將會增加
我們的解決方法是讓異常處理方法獨立開來如
public class NestedExceptionHandling
{
public void MainMethod()
{
try
{
//some implementation
ChildMethod();
}
catch(Exception exception)
{
//Handle exception
}
}
private void ChildMethod()
{
//some implementation
ChildMethod();
}
private void ChildMethod()
{
//some implementation
}
}
大數據量上使用Dataset和DataReader混用當單表數據量很大的情況使用DataSet是一種很不明智的選擇應為DataSet是以DataTable內存形式存放數據量一次性將數據拖入內存當數據很大的情況下這種方式是很吃內存的相比DataSerDataReader就顯得優雅很多它是每次讀取一條數據然後輪詢調用機制但是也有它的弊端就是相對長連接但是對內存消耗而言這是有利的當然DataSet在大部分應用場景下也是有自己的優點充分解耦一次性操作領域模型操作等方面兩者分情況分場景而用這裡只是稍微提提根據場景分析區別
From:http://tw.wingwit.com/Article/program/ASP/201311/21846.html