Effective C#

  • 13937
  • 0
  • C#
  • 2010-05-12

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#中for和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:記憶體回收

.NET Framework記憶體回收機制

 

‧Item15 - Use StructLayout attribute, for classes and structs, when using COM Interop.


在引用非.Net的外部元件,尤其是會牽涉到記憶體的元件,請使用 [StruckLayout(LayoutKind.Sequential)]來控制實際配置位置

MSDN:StructLayoutAttribute 類別

[API]調用 Win32 API DLL (二)

 

DotBlog 的標籤: