1. 程式人生 > >Util應用程式框架公共操作類(一):資料型別轉換公共操作類(介紹篇)

Util應用程式框架公共操作類(一):資料型別轉換公共操作類(介紹篇)

  本系列文章將介紹一些對初學者有幫助的輔助類,這些輔助類本身並沒有什麼稀奇之處,如何能發現需要封裝它們可能更加重要,所謂授之以魚不如授之以漁,掌握封裝公共操作類的技巧才是關鍵,我會詳細說明建立這些類的動機和思考過程,以幫助初學者發現和封裝自己需要的東西。建立公共操作類的技巧,大家可以參考我的這篇文章——應用程式框架實戰十二:公共操作類開發技巧(初學者必讀)

  封裝公共操作類,不僅要把技術上困難的封裝進來,還需要不斷觀察自己的程式碼,以找出哪些部分可以更加簡化。本文將介紹一個容易被大家所忽視的東西——資料型別轉換。

  資料型別轉換可以把某個源型別轉換為目標型別,比如把字串轉換為整型。一種選擇是,你可以使用System.Convert類進行轉換。  

string input = "1";
int result = System.Convert.ToInt32( input);

這樣看起來好像沒什麼問題,不過input很明顯不一定是個常量,如果你還在使用ASP.NET Web Form這樣的技術,你需要在後置程式碼中從控制元件讀取值。

string input = TextBox1.Text;
int result = System.Convert.ToInt32( input);

  當客戶輸入整數時,不會有什麼問題,但他如果輸入一個字母或漢字,上面程式碼會丟擲一個異常,“System.FormatException: 輸入字串的格式不正確。”,這可能不是你想要的。當然,你可以在客戶端進行JS驗證,不過客戶也可以繞過你的頁面,直接POST到你的伺服器,所以你在服務端必須處理這個問題。

  引發異常,並且你沒有進行任何處理,可能導致一個黃頁,讓你的客戶一驚。為了避免顯示黃頁,初學者大多直接在程式碼上加一個try-catch進行捕獲,並給客戶一個友情提示。

try {
  string input = TextBox1.Text;
  int result = System.Convert.ToInt32( input );
}
catch( Exception ex ) {
  //彈出訊息框提示客戶輸入正確資料
}

  一旦吃到甜頭,初學者發現這段程式碼可以實現他要的功能,不會過多考慮可維護性,於是會把這個結構向整個表現層複製,最終導致一個混亂的局面。

  除了表現層以外,資料訪問層也經常需要進行資料型別轉換。如果你還在使用原始的Ado.Net,從DataReader獲取值。

IDataReader reader = cmd.ExecuteReader();
int result = System.Convert.ToInt32( reader["欄位名"] );

  同樣,為了不引發異常,初學者根據之前的經驗,會在呼叫程式碼時新增try-catch進行異常捕獲。

try {
  IDataReader reader = cmd.ExecuteReader();
  int result = System.Convert.ToInt32( reader["欄位名"] );
}
catch( Exception ex ) {
  //有些人會在這裡記錄錯誤日誌,還有些懶人直接留空,啥也不幹
}        

  所以最終的結果是,只要進行資料型別轉換的操作,初學者為了一定的系統健壯性會大量新增異常處理結構,從而導致程式碼混亂。

  另一個選擇是,.Net提供了一個不引發異常的型別轉換方法,比如,

string input = "1";
int result;
if( int.TryParse( input, out result ) == false ){
  //處理錯誤
}

  TryParse會返回一個bool值,指示轉換是否成功,如果轉換失敗,你可以記錄日誌,並顯示一個錯誤。不過大部分人都可能會偷懶,不會在這裡進行任何處理。

string input = "1";
int result;
int.TryParse( input, out result );

  如果你不想引發異常,更不想用try-catch結構來捕獲異常,這確實是一個更好的選擇,但需要額外定義一個變數,作為out引數來獲取值,會造成額外的工作量。

  當然,.Net技術也一直處於持續改進中,表現層技術進入到MVC和WPF時代,而資料訪問技術也進入到了Entity Framework時代。MVC提供了一個叫做模型繫結的功能,用於將介面上傳回的資料對映到控制器操作的引數中,並且這些引數可以支援實體,這是一個非常強大的功能,這樣就不需要手工進行賦值了,更不需要型別轉換。WPF通過雙向資料繫結,Entity Framework通過對映器,都解決了類似問題。

  但是,並不是說資料型別轉換就毫無用武之地了,考慮一個使用MVC的場景。你在介面上有一個表格,表格的每行都有一個checkbox,你可以打勾以選中某些行,然後你會把每行的實體標識傳到控制器。如果實體標識的資料型別使用Guid,你可以用一個IList<Guid>來接收。

public ActionResult 方法名( IList<Guid> ids ) {
}

  這一般都行得通。但是,你並不總是可以這樣幹,出於某些特殊原因,有時候你需要自己在js中用逗號拼接一些Id,或者用一個Hidden把用逗號拼接的Id儲存起來,然後作為一個字串傳到控制器。比如” 06d8dcdd-cfad-433c-aec0-87bf613b9457, 684c0c02-93ec-4047-8f16-57e36b50d703”。

public ActionResult 方法名( string ids ) {
}

  由於沒有自動轉換支援,你只好自己動手,這很簡單,使用逗號把輸入字串打散成字串陣列,然後遍歷每個陣列元素,轉換成Guid型別,再新增到一個結果集合儲存起來就OK了。

public ActionResult 方法名( string ids ) {
  List<Guid> result = new List<Guid>();
  string[] list = ids.Split( ',' );
  foreach( var each in list ) {
    result.Add( Guid.Parse( each ) );
  }
  //在這裡把result傳到業務層
}

  你發現這段程式碼不僅可以處理帶有逗號的字串,像” 06d8dcdd-cfad-433c-aec0-87bf613b9457, 684c0c02-93ec-4047-8f16-57e36b50d703”,甚至還能處理不帶逗號的,比如“06d8dcdd-cfad-433c-aec0-87bf613b9457 “。你非常滿意,然後把這一段程式碼複製到所有需要將拼接字串轉換成集合的地方。

  沒過多久,你在一個頁面發現了Bug,以前測試的時候,都是操作多個Id,這次沒進行操作,傳過來的字串是””,你的程式碼沒有進行任何健壯性檢測,所以失敗了,丟擲一個異常“無法識別的 GUID 格式。“。

  你安慰自己“這並不算什麼技術問題,只是一時疏忽,看我加一個判斷,一招將它搞定“。不過在你的下意識裡,已經感覺到進行邊界測試才是健壯性的關鍵。

public ActionResult 方法名( string ids ) {
  List<Guid> result = new List<Guid>();
  if ( !string.IsNullOrWhiteSpace( ids ) ) {
    string[] list = ids.Split( ',' );
    foreach( var each in list ) {
      result.Add( Guid.Parse( each ) );
    }
  }
  //在這裡把result傳到業務層
}

  你現在準備測試一下,傳了一個””過來,果然有效,你大讚自己處理BUG的速度驚人,為了給其它地方也新增如此健壯的特性,你開啟所有可能用到的頁面,找到這幾行程式碼,進行修改,雖然你感覺這確實有點無聊,但還是隻有硬起頭皮改了。

  從上面可以看到,雖然是司空見慣的資料型別轉換,也還是有很多值得我們改進的地方。

  下一篇我將使用TDD方式把資料型別轉換公共操作類開發出來。由於TDD並不是本系列介紹的重點,所以我不會在本文中詳細介紹TDD的要點,請大家檢視相關資料,如果有空,我會專門寫一篇文章來分享我在使用TDD所碰到的障礙以及心得。

  .Net應用程式框架交流QQ群: 386092459,歡迎有興趣的朋友加入討論。

  謝謝大家的持續關注,我的部落格地址:http://www.cnblogs.com/xiadao521/