Effective C#
其實一開始是在找Effective C#這本書…結果發現CodeProject上面有不錯的文章,有幾點是蠻常用的,另外還有後來其它人討論過,有別的意見的,就整理一下跟大家分享一下:D
來源:http://www.codeproject.com/KB/cs/effectivecspart1.aspx
‧Item1 - Prefer the Length property when checking string size. [Performance]
‧Item2 - Prefer StringBuilder over string concatenation. [Performance]
‧Item3 - Avoid Boxing and UnBoxing as much as possible. [Performance]
‧Item4 - Prefer String.Equal method over == operator. [Performance]
‧Item5 - Use Native Image Generator (Ngen.exe) in case of long and heavy initialization. [Performance]
‧Item6 - Prefer 'for' over 'foreach'. [Performance] <<有待討論
‧Item7 - Prefer the 'as' operator over direct type casting. [Usage]
‧Item8 - Use the 'checked' keyword to avoid overflow. [Usage]
‧Item9 - Use the 'is' operator before casting. [Usage]
‧Item10 - Use Explicit interface to 'hide' the implementation of an interface. [Usage]
‧Item11 - Use @ to ease the work with literal paths. [Usage]
‧Item12 - Make your API assembly CLS compliant. [Usage]
‧Item13 - Define destructor and implement IDisposable interface for classes that use native resources directly. [Garbage Collection]
‧Item14 - Avoid the use of GC.Collect [Garbage Collection]
‧Item15 - Use StructLayout attribute, for classes and structs, when using COM Interop. [COM Interop]
‧Item1 - Prefer the Length property when checking string size. (使用Length屬性來判斷字串大小。)
通常判斷字串是否為空有好幾個方法,如果確認字串不可能為null,則使用Length; 如果可能為null,則使用String.IsNullOrEmpty。
儘量不要直接使用!=。
if(str != "") {};
if(str.Length > 0) {};
if(!String.IsNullOrEmpty(str)) {};
[Performance][VB.NET].NET空字串判斷徹底研究
‧Item2 - Prefer StringBuilder over string concatenation. (使用StringBuilder來進行字串連接)
在大量文字串接的時候,儘量使用StringBuilder,比較簡省效能,不過有時候還是要依據不同的狀況而定。
可以參考
StringBuilder串接字串的迷思
String與Stringbuilder組字串的效能比較
//NO
String strConcat;
ArrayList arrayOfStrings = new ArrayList();
arrayOfStrings.Add("a");
arrayOfStrings.Add("b");
foreach (string s in stringContainer) {
strConcat += s;
}
//YES
StringBuilder sbConcat = new StringBuilder ();
foreach (string s in arrayOfStrings ) {
sbConcat.append(s);
}
‧Item3 - Avoid Boxing and UnBoxing as much as possible.(儘量避免使用boxing及unboxing)
在使用已知的型別,儘量宣告明確型別,避免系統需要一直進行型別轉換。
//NO
struct st { public int i; }
Arraylist arr = new ArrayList();
for (int i=0 ; i< count; i++) {
st s;
s.i = 4;
arr.item.add(st) ; //<- Boxing (Allocating an object instance
// + copying the value-type value into that instance)
}
st obj = (st ) arr[0]; //<- Unboxing (casting and copy)
//YES
//Decalre the data type as class.
Class st { public int i; }
‧Item4 - Prefer String.Equal method over == operator. (在進行字串比較是否相同時,儘量使用String.Equal)
if (str.CompareTo(str2) == 0) {}
if (str.Equals(str2)) {}
if (str == str2) {}
通常我們在進行字串比較的時候,會採用以上幾種方法,不過有什麼差異呢?
請參閱MSDN:HOW TO:比較字串 (C# 程式設計手冊)
91大補充:如果是要比較不分大小寫的字串有沒相同,記得用String.Compare(),會比toUpper轉一次在比一次的動作效率好。
Item5 - Use Native Image Generator (nGen.exe) in case of long and heavy initialization.
因為.Net Framework執行C#時使用JIT進行編譯,每段程式執行前都會被編譯;為了避免大量和長時間的初始化,可以使用nGen.Net。
MSDN:原生映像產生器
(不過我沒有使用過,不知道有沒有人能分享一下?)
Item6 - Prefer 'for' over 'foreach'. (能使用for時儘量不用foreach)
關於這點,就比較值得討論;大部份人測試的結果還是推薦用foreach。而在Effective C#一書中,也以foreach優先。
[C#]Effective C# 條款十一: 優先採用foreach迴圈
註:連CSDN都有吵過XD
‧Item7 - Prefer the 'as' operator over direct type casting. (轉型時使用as而不直接強制轉型)
如果強制轉型失敗,會發生exception;而用as(is)則最壞的情況會回傳null。
//NO
object o = 1.3;
try
{
string str = (string)o;
}
catch(InvalidCastException ex){...}
//YES
string str = o as string;
if(null != str){...}
[C#]Effective C# 條款三: 運算子is或as優於強制轉型
‧Item8 - Use the 'checked' keyword to avoid overflow. (使用checked關鍵字來避免溢位)
這個應該就......不用多說了吧XD
‧Item9 - Use the 'is' operator before casting. (在強制轉型時先使用is判斷)
在撰寫程式時,要儘量不要使用強制轉型,若是一定要使用,最好也先進行型別判斷。
public class Preson{int nAge;}
//No:
static void main(object o){
try {
(Person)o.nAge = 45;
}
catch(InvalidCastException ex){...}
}
//Yes:
static void func(object o)
{
if ( true == (o is Person) )
{
(Person)o.nAge = 45;
}
}
‧Item10 - Use Explicit interface to 'hide' the implementation of an interface. (請看回覆討論)
//interface definition
Public interface IChild{
bool IsHuman();
void lie();
}
//class definition
Pubic Pinocchio: IChild {
IChild.IsHuman() //explicit interface implementation
{
}
public void Lie(); //regular interface implementation
}
//using the object
static void main()
{
// Visual studio will not display
// the isHuman mwthod in the intellisence.
Pinocchio o = new Pinocchio();
((IChild) o).IsHuman(); // using the IsHuman method explicitly.
o.Lie();
}
‧Item11 - Use @ to ease the work with literal paths.(使用@在宣告路徑時更便利)
其實不光是路徑,有時候碰到換行處理時也會方便很多。
//Old way
string sFilePath = "c:\\a\\b\\c.txt";
string aaa = "aa\r\nbb";
//The C# way
string sFilePath = @"c:\a\b\c.txt";
string aaa = @"aa
bb";
‧Item12 - Make your API assembly CLS compliant.(以 CLSCompliant 標記組件)
Common Language Specification (CLS) 會定義命名限制、資料型別及組件必須遵守的規則 (如果組件會使用於跨程式設計語言時)。
良好的設計會要求所有組件使用 CLSCompliantAttribute 明確表示 CLS 標準的符合性。如果該屬性未出現於組件中,則表示組件不符合 CSL 標準。
MSDN: 以 CLSCompliant 標記組件
using System;
[assembly:CLSCompliant(true)]
namespace DesignLibrary {}
‧Item13 - Define destructor and implement IDisposable interface for classes that use native resources directly.
如果你的物件使用了較多的外部資源,記得定義解構式及實作 Dispose 方法,以避免浪費資源。
‧Item14 - Avoid the use of GC.Collect (避免使用GC.Collect方法)
其實.Net本身就有制定回收的機制,在不確定的清況下,不要隨便使用GC.Collect,有時候反而會拖累效能。
MSDN:記憶體回收
‧Item15 - Use StructLayout attribute, for classes and structs, when using COM Interop.
在引用非.Net的外部元件,尤其是會牽涉到記憶體的元件,請使用 [StruckLayout(LayoutKind.Sequential)]來控制實際配置位置