以下是本人對.Net平臺開發(fā)實(shí)踐的一些點(diǎn)滴總結(jié)。這里的技術(shù)規(guī)范主要是開發(fā)過程的代碼規(guī)范、數(shù)據(jù)庫設(shè)計(jì)規(guī)范、Com和.Net互操作規(guī)范;實(shí)踐精華是對技術(shù)實(shí)踐過程中的部分總結(jié)。
良好的代碼風(fēng)格來自于同一的代碼規(guī)范。風(fēng)格良好的代碼不僅具備可讀性和可維護(hù)性,同時(shí)也給人行云流水、賞心悅目之快感。
據(jù)Microsoft公司統(tǒng)計(jì),基于微軟平臺的開發(fā)中,有70-80%的印度工程師在完成同類算法或者模塊時(shí),使用的代碼基本一致;而相同的調(diào)查中只有20%的中國工程師們是基本一致的。這說明我們的代碼生產(chǎn)過程亟待規(guī)范。
類型、變量、常量、方法等標(biāo)識符一律采用對應(yīng)的英文實(shí)義;如果涉及到兩個(gè)獨(dú)立的實(shí)義單詞,則中間用下劃線間隔或者單詞首字母大寫(兩種方式都可以);如果標(biāo)識符的長度超過了30個(gè)字母,則基本上以英文單詞發(fā)音的重讀音節(jié)取選出三個(gè)字母,如Repeater用rpt,Management用mgt。
目前一般有兩種大小寫規(guī)則:
Pascal大小寫形式,所有單詞第一個(gè)字母大寫,其他字母小寫。
Camel大小寫形式,除了第一個(gè)單詞,所有單詞第一個(gè)字母大寫,其他字母小寫。
n 類名使用Pascal大小寫形式
public class HelloWorld(或者Hello_World,以下同,不再贅述)
{
...
}
n 方法使用Pascal大小寫形式
public class HelloWorld()
{
void SayHello(string name)
{
...
}
}
n 變量和方法參數(shù)使用Camel 大小寫形式
public class HelloWorld()
{
int totalCount = 0;
void SayHello(string name)
{
string fullMessage = "Hello " + name;
...
}
}
n 不要使用匈牙利方法來命名變量
以前,多數(shù)程序員喜歡把數(shù)據(jù)類型作為變量名的前綴而m_作為成員變量的前綴。例如: string m_sName;int nAge;
然而,這種方式在.NET編碼規(guī)范中是不推薦的。所有變量都用Camel 大小寫形式,而不是用數(shù)據(jù)類型和m_來作前綴。
用name,address,salary等代替nam,addr,sal。
別使用單個(gè)字母的變量象i,n,x 等。使用 index,temp等。用于循環(huán)迭代的變量例外:
如果變量只用于迭代計(jì)數(shù),沒有在循環(huán)的其他地方出現(xiàn),允許用單個(gè)字母的變量命名,而不是另外取實(shí)義名。
文件名要和類名匹配,例如,對于類HelloWorld,相應(yīng)的文件名應(yīng)為helloworld.cs。
n 縮進(jìn)用TAB,不用 SPACES。
n 注釋需和代碼對齊。
n 遵循VS2005的自動(dòng)對齊規(guī)則,不要人為的調(diào)整。
n 用一個(gè)空行來分開代碼的邏輯分組。
n 在一個(gè)類中,各個(gè)方法的實(shí)現(xiàn)體必須用空行間隔,大括弧“{}”需獨(dú)立一行。
n 在每個(gè)運(yùn)算符和括號的前后都空一格。如:
If ( showResult == true )
{
for ( int i = 0; i < 10; i++ )
{
//
}
}
而不是:
if(showResult==true)
{
for(int i= 0;i<10;i++)
{
//
}
}
n 避免使用大文件。如果一個(gè)文件里的代碼超過300~400行,必須考慮將代碼分開到不同類中。
n 避免寫太長的方法。一個(gè)典型的方法代碼在1~30行之間。如果一個(gè)方法發(fā)代碼超過30行,應(yīng)該考慮將其分解為不同的方法。
n 方法名需能看出它作什么。別使用會(huì)引起誤解的名字。如果名字一目了然,就無需用文檔來解釋方法的功能了。
n 一個(gè)方法只完成一個(gè)任務(wù)。不要把多個(gè)任務(wù)組合到一個(gè)方法中,即使那些任務(wù)非常小。
n 使用C# 的特有類型,而不是System命名空間中定義的別名類型。如:
int age;
string name;
object contactInfo;
而不是:
Int16 age;
String name;
Object contactInfo;
這么做是基于如下兩點(diǎn)原因:(1)規(guī)范性和一致性;(2)便于跨語言平臺的移植。
n 別在程序中使用固定數(shù)值,用常量代替。別用字符串常數(shù),盡量用資源文件。
n 避免使用很多成員變量,聲明局部變量,并傳遞給方法。
n 不要在方法間共享成員變量,如果在幾個(gè)方法間共享一個(gè)成員變量,那就很難知道是哪個(gè)方法在什么時(shí)候修改了它的值。必要時(shí)使用enum,別用數(shù)字或字符串來指示離散值。
n 別把成員變量聲明為 public或 protected。都聲明為private 而使用 public/protected 的Properties。
n 不在代碼中使用具體的路徑和驅(qū)動(dòng)器名,使用相對路徑,并使路徑可編程。永遠(yuǎn)別設(shè)想你的代碼是在"C:"盤運(yùn)行。你不會(huì)知道,一些用戶在網(wǎng)絡(luò)或"Z:"盤運(yùn)行程序。
n 應(yīng)用程序啟動(dòng)時(shí)作些“自檢”并確保所需文件和附件在指定的位置。必要時(shí)檢查數(shù)據(jù)庫連接,出現(xiàn)任何問題給用戶一個(gè)友好的提示。
n 如果需要的配置文件找不到,應(yīng)用程序需能自己創(chuàng)建使用默認(rèn)值。如果在配置文件中發(fā)現(xiàn)錯(cuò)誤值,應(yīng)用程序要拋出錯(cuò)誤,給出提示消息告訴用戶正確值。錯(cuò)誤消息需能幫助用戶解決問題。
n 別每行代碼,每個(gè)聲明的變量都做注釋。在需要的地方注釋。
n 可讀性強(qiáng)的代碼需要很少的注釋,如果所有的變量和方法的命名都很有意義,會(huì)使代碼可讀性很強(qiáng)并無需太多注釋。行數(shù)不多的注釋會(huì)使代碼看起來優(yōu)雅。
n 如果因?yàn)槟撤N原因使用了復(fù)雜艱澀的原理,必須為程序配備良好的文檔和詳細(xì)的注釋。
n 對注釋做拼寫檢查,保證語法和標(biāo)點(diǎn)符號的正確使用。
n 數(shù)據(jù)表的分類
u 系統(tǒng)表 支撐業(yè)務(wù)模型的數(shù)據(jù)表,如流程模型、系統(tǒng)管理相關(guān)表。
u 業(yè)務(wù)表 產(chǎn)品提供的針對業(yè)務(wù)的通用功能模塊相關(guān)表,如通用業(yè)務(wù)查詢等。
u 用戶表 用戶二次開發(fā)使用的與具體業(yè)務(wù)相關(guān)的數(shù)據(jù)表。
n 數(shù)據(jù)表的命名
u 所有表格命名一律以字母“T”開頭(Table),并且用實(shí)義單詞以下劃線“_”間隔。
u 系統(tǒng)表 系統(tǒng)表前綴為:TSYS_
u 業(yè)務(wù)表前綴為:TBIZ_
u 用戶表由用戶自行定義,但是建議不要與系統(tǒng)表和業(yè)務(wù)表的命名規(guī)則重復(fù)。
n 字段的命名
字段的命名規(guī)則參照代碼標(biāo)識符的命名規(guī)則,但是注意避開數(shù)據(jù)庫的保留字。比如不要采用這樣的字段名:index,field,password,id,Oracle,SQL等等。
對于涉及到技術(shù)核心的系統(tǒng)表,為了防止剖析,建議采用類似“F1,F2,F3……Fn”的方式命名。但是不要采用“F
n 索引是一把雙刃劍,索引將提高查詢的效率,但是卻降低了insert/delete/update 的效率。
n 通常情況下,對數(shù)據(jù)的編輯頻度和時(shí)限要求遠(yuǎn)遠(yuǎn)低于對數(shù)據(jù)庫的查詢要求,因此對于記錄很多且頻繁查詢的數(shù)據(jù)表,必須建立索引。
n 大多數(shù)數(shù)據(jù)庫為主鍵字段自動(dòng)創(chuàng)建索引,注意為外鍵創(chuàng)建索引。
n 不要索引大字段,這樣作會(huì)讓索引占用太多的存儲(chǔ)空間。
n 盡量不要索引頻繁編輯的小型表。
n identify字段不要作為表的主鍵與其它表關(guān)聯(lián),這將會(huì)影響到該表的數(shù)據(jù)遷移。如果考慮支持多數(shù)據(jù)庫,建議主鍵采用程序生成的唯一值。
n 如果一個(gè)大型表需要頻繁的做insert/delete/update操作,同時(shí)也需要做高并發(fā)量的查詢,那么建議根據(jù)數(shù)據(jù)的訪問頻度對表作拆分,而后建立索引。
數(shù)據(jù)庫廠商為了凸現(xiàn)自身的優(yōu)勢,都提供了豐富且個(gè)性化的過程與函數(shù)。
為了提升產(chǎn)品的伸縮性和數(shù)據(jù)無關(guān)性,請不要使用與特定數(shù)據(jù)庫相關(guān)的過程與函數(shù),也不推薦采用Store Procedure,建議使用應(yīng)用服務(wù)器的中間層業(yè)務(wù)對象。
n 盡量避免使用Blob,如果一定要用,請不要索引blob,并且不要定義多個(gè)blob。
n 不要使用日期字段,改用字符串char(19)替代,如:2008-12-09 12:22:08。
n 對于確定長度的串,請固定字段類型的長度,如char(80),不要采用varchar。
n 對于值類型字段,請使用對應(yīng)的數(shù)據(jù)庫值類型,而不要用字符串。
.NET 技術(shù)已經(jīng)成為微軟平臺的主流,但是在Win32時(shí)代開發(fā)了很多COM、DCOM組件,由于在開發(fā)COM組件時(shí)投入了大量的人力、財(cái)力,如何在.NET環(huán)境下重用這些COM組件就顯得更有意義。
.NET支持運(yùn)行時(shí)通過COM、COM+、本地WinAPI調(diào)用與未托管代碼的雙向互操作性,要實(shí)現(xiàn)互操作性,必須首先引入.NET Framework的 System.Runtime.InteropServices命名空間。
C#的語法為:
using System.Runtime.InteropServices;
(1).NET訪問API
.NET允許C#訪問未托管的DLL的函數(shù)。如要調(diào)用Windows User32.dll的MessageBox函數(shù):
int MessageBox(HWND hwnd,LPCTSTR lpText, LPCTSTR lpCaption,UINT uType)
可以聲明一個(gè)具有DLLImport屬性的static extern方法:
using System.Runtime.InteropServices;
[DllImport(“user32.dll”)]
static ertern int MessageBox(int hwnd,string text,string caption,int type);
然后在代碼里面直接調(diào)用就可以了。這里要注意在調(diào)用返回字符串的API中使用StringBuilder對象。
(2).NET訪問COM組件
從.NET調(diào)用COM組件比較容易,只要使用tlbimp.exe產(chǎn)生COM的裝配形式的WarpClass,然后在.NET項(xiàng)目中調(diào)用即可。
注意COM的類型信息通過Type Library文件描述,.NET裝配件是自描述的。Tlbimp的作用是從COM組件及其類型信息中產(chǎn)生自描述的裝配件。
1.編寫Com組件
編譯生成一個(gè)ComAccount.dll。
2. 產(chǎn)生.NET可訪問的包裝類(assembly),使用TlbImp.exe產(chǎn)生.NET裝配件。
TlbImp /out:NetAccount.dll ComAccount.dll
3.在.NET代碼中訪問
.NET代碼只需引用NetAccount.dll,就可以像訪問.NET的裝配件一樣訪問COM組件。
n 在應(yīng)用程序級(線程級)錯(cuò)誤處理器中處理所有的一般異常。遇到“意外的一般性錯(cuò)誤”時(shí),此刻錯(cuò)誤處理器應(yīng)該捕捉異常,給用戶提示消息,在應(yīng)用程序關(guān)閉或用戶選擇“忽略并繼續(xù)”之前記錄錯(cuò)誤信息。
n 不必每個(gè)方法都用try-catch,當(dāng)特定的異??赡馨l(fā)生時(shí)才使用。比如,當(dāng)寫文件時(shí),處理異常FileIOException。
n 別寫太大的 try-catch 模塊。如果需要,為每個(gè)執(zhí)行的任務(wù)編寫單獨(dú)的 try-catch 模塊。這將有助于找出哪一段代碼產(chǎn)生異常,并給用戶發(fā)出特定的錯(cuò)誤消息。
n 如果應(yīng)用程序需要,可以編寫自己的異常類。自定義異常不應(yīng)從基類SystemException派生,而要繼承于IApplicationException。
n 在開發(fā)階段,不必在所有方法中捕捉一般異常??桃獾姆趴v異常,將幫助在開發(fā)周期發(fā)現(xiàn)大多數(shù)的錯(cuò)誤。
n 不要捕捉了異常卻什么也不做,看起來系統(tǒng)似乎在正常運(yùn)行。如果這樣隱藏了一個(gè)異常,將永遠(yuǎn)不知道異常到底是否發(fā)生,為什么發(fā)生。
n 發(fā)生異常時(shí),給出友好的消息給用戶。但要精確記錄錯(cuò)誤的所有可能細(xì)節(jié),包括發(fā)生的時(shí)間,和相關(guān)方法,類名等。
n 永遠(yuǎn)別用像“應(yīng)用程序出錯(cuò)”,“發(fā)現(xiàn)一個(gè)錯(cuò)誤”等錯(cuò)誤提示消息,而應(yīng)給出類似“更新數(shù)據(jù)庫失敗,請確保登陸id和密碼正確。”之類的具體消息。
n 顯示錯(cuò)誤消息時(shí),還應(yīng)提示用戶如何解決問題。如:“更新數(shù)據(jù)庫失敗,請確保登陸id和密碼正確。”,而不是僅僅說“更新數(shù)據(jù)庫失敗”。
n 顯示給用戶的消息要簡短而友好。但要把所有可能的信息都記錄下來,以助診斷問題。
推薦如下異常處理模式:
void ReadFromFile ( string fileName )
{
try
{
// 讀文件.
}
catch (FileIOException ex)
{
// 記載異常日志
// 重拋具有針對性的異常信息
throw;
}
}
不推薦如下的異常處理模式:
void ReadFromFile ( string fileName )
{
try
{
// 讀文件
}
catch (Exception ex)
{
// 捕捉一般異常將讓我們永遠(yuǎn)不知道到底是文件錯(cuò)誤還是其他錯(cuò)誤
// 隱藏異常將我們永遠(yuǎn)不知道有錯(cuò)誤發(fā)生。
return "";
}
}
.Net平臺的垃圾回收機(jī)制,可以自動(dòng)的dispose不再引用的對象實(shí)例,所以很多開發(fā)人員并不主動(dòng)釋放申請的對象資源。事實(shí)上,在對象的生命周期結(jié)束之前是不會(huì)被釋放的。
但是,很多時(shí)候當(dāng)對象處于生命周期之內(nèi)時(shí),我們不再使用它,以便釋放資源提升系統(tǒng)效率。因此,主動(dòng)釋放申請的資源顯得很有必要。
永遠(yuǎn)不要把力所能及的事情交給操作系統(tǒng),及時(shí)釋放不再使用的資源是一個(gè)好習(xí)慣。
數(shù)據(jù)庫訪問永遠(yuǎn)是系統(tǒng)的瓶頸,選擇高效、穩(wěn)健的數(shù)據(jù)庫訪問模式是產(chǎn)品性能的基礎(chǔ)保證。
n 永遠(yuǎn)不要假設(shè)你的應(yīng)用系統(tǒng)構(gòu)建與某個(gè)數(shù)據(jù)庫之上,因此必須有統(tǒng)一的、透明的數(shù)據(jù)庫訪問機(jī)制。
n 采用ADO.Net訪問數(shù)據(jù)庫 基于效率和穩(wěn)定性的考量,采用微軟平臺原生的數(shù)據(jù)庫訪問模式ADO.Net。使用ADO.Net可以通過OLEDB和ODBC兩種模式訪問數(shù)據(jù)庫,我們建議使用數(shù)據(jù)庫廠商提供的OLEDB模式,這種模式繞過了ODBC,使得數(shù)據(jù)庫的游標(biāo)性能大大提升,效率更佳。
n 不使用第三方的數(shù)據(jù)持久層 使用類似于Nhibernate之類的第三方數(shù)據(jù)持久層工具雖然可以提高開發(fā)的效率,但是卻降低了系統(tǒng)的性能和彈性。性能對于產(chǎn)品而言,遠(yuǎn)遠(yuǎn)比開發(fā)效率重要的多,況且基于VS2005的開發(fā),效率不是問題。請記?。旱谌降墓ぞ哂肋h(yuǎn)不能成為你的產(chǎn)品核心技術(shù);數(shù)據(jù)訪問機(jī)制是系統(tǒng)的效率瓶頸,對
n 使用自主產(chǎn)權(quán)的數(shù)據(jù)對象 直接采用ADO.Net封裝最底層的數(shù)據(jù)訪問方法:插入、刪除和更新,以及事務(wù)管理等;客戶端和服務(wù)器端采用相同的數(shù)據(jù)訪問機(jī)制,并設(shè)立連接緩沖池提升數(shù)據(jù)訪問效率。
對于多層分布式應(yīng)用而言,數(shù)據(jù)庫事務(wù)呈現(xiàn)出“遠(yuǎn)程、分布”的特色,導(dǎo)致事務(wù)難以管理。
對于Ado.Net而言,事務(wù)綁定了數(shù)據(jù)庫連接,因此必須在數(shù)據(jù)訪問對象中對每一個(gè)數(shù)據(jù)庫連接管理各自的事務(wù)或嵌套事務(wù)。如果要訪問數(shù)據(jù)庫,服務(wù)器上的數(shù)據(jù)訪問對象將自動(dòng)分配一個(gè)特定的連接,根據(jù)該連接ID執(zhí)行數(shù)據(jù)操作;無論該事務(wù)分布于多少個(gè)遠(yuǎn)程客戶端進(jìn)程,服務(wù)器數(shù)據(jù)對象只需要鎖定連接ID即可輕松進(jìn)行事務(wù)管理。
智能客戶端是易于部署和管理的客戶端應(yīng)用程序,它綜合了瘦客戶端和胖客戶端的優(yōu)點(diǎn),通過統(tǒng)籌使用本地資源和到分布式數(shù)據(jù)資源的智能連接,提供快速響應(yīng)的和豐富的交互式體驗(yàn)。
智能客戶端分為Windows Form,Office Client,Mobile Client三種類型,具有如下特點(diǎn):
n 利用本地資源
n 利用網(wǎng)絡(luò)資源
n 支持偶爾連接的用戶
n 提供智能安裝和更新
n 提供客戶端設(shè)備靈活性
.NET 框架基類庫內(nèi)嵌了支持智能客戶端的豐富程序集,通過使用公共語言運(yùn)行庫 (CLR),可以利用任何受到 .NET 支持的語言來開發(fā)智能客戶端。
智能客戶端是瘦客戶段的強(qiáng)大替代品,也是微軟推薦的客戶端模式。盡量使用智能客戶端而不要使用瀏覽器。如果可以,請把你的客戶端系統(tǒng)構(gòu)建在Office平臺上,如Outlook。