泛型委托基礎
class Program
class Program { // 泛型委托,與普通委托類似,不同之處只在於使用泛型委托要指定泛型參數 public delegate T MyGenericDelegate<T>(T obj1,T obj2); int AddInt(int x, int y) { return x + y; } string AddString(string s1, string s2) { return s1 + s2; } static void Main(string[] args) { Program p = new Program(); MyGenericDelegate<int> intDel; intDel = p.AddInt; Console.WriteLine("int代理的值是{0}", intDel(100, 200)); MyGenericDelegate<string> stringDel; stringDel = p.AddString; Console.WriteLine("string代理的值是{0}", stringDel("aaa", "bbb")); } }
為了方便開發,.NET基類庫針對在實際開發中最常用的情形提供了幾個預定義好的委托,這些預定義委托用得很廣,比如在編寫lambda表達式和開發並行計算程序時經常要用到他們。
.NET提供的泛型委托包括action和func
感悟:對泛型委托基本屬於有點認識,但從來沒真正在項目中使用過,有時感覺沒有合適的場景應用,但看了artech兄的文章,我才明白,原來泛型委托真的可以做很多事情,而且效果往往是沒有使用委托所達不到的。
Action<T> 泛型委托:封裝一個方法,該方法只采用一個參數並且不返回值。可以使用此委托以參數形式傳遞方法,而不用顯式聲明自定義的委托。該方法必須與此委托定義的方法簽名相對應。也就是說,封裝的方法必須具有一個通過值傳遞給它的參數,並且不能返回值。當然泛型委托不只是只能支持一個參數,它最多可以支持四個參數。
泛型委托與直接顯示聲明自定義委托的示例比較:
1:顯示聲明自定義委托:
delegate void DisplayMessage(string message); public class TestCustomDelegate { public static void Main() { DisplayMessage messageTarget; messageTarget = ShowWindowsMessage; messageTarget("Hello, World!"); } private static void ShowWindowsMessage(string message) { MessageBox.Show(message); } }
2: Action<T> 用法。比起自定義委托,明顯可以看出代碼簡潔了。
public class TestAction1 { public static void Main() { Action<string> messageTarget; messageTarget = ShowWindowsMessage; messageTarget("Hello, World!"); } private static void ShowWindowsMessage(string message) { MessageBox.Show(message); } }
Func<T, TResult> 委托:封裝一個具有一個參數並返回 TResult 參數指定的類型值的方法。同理,這裡的泛型委托只是接受一個參數的委托,它最多同樣支持四個參數。TResult:此委托封裝的方法的返回值類型。
問題:目前本公司在寫程序時,都使用了log4net,我想大家在做異常時,都會利用try catch來捕獲異常,日志就在catch塊中完成,但每個方法都寫一堆的try catch往往顯的有點別扭。雖然寫程序時提倡盡量去捕獲具體的錯誤異常,但總會有你預想不到的異常拋出,為此直接捕獲Exception算是不錯的做法。
具體場景:在客戶端調用WCF服務時,我們都需要在客戶做異常處理,最常見的錯誤異常為CommunicationException,TimeoutException,Exception示例如下:
try { //執行方法調用 ...... (proxy as ICommunicationObject).Close(); } catch (CommunicationException ex) { (proxy as ICommunicationObject).Abort(); WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常CommunicationException:" + ex.ToString()); } catch (TimeoutException ex) { (proxy as ICommunicationObject).Abort(); WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據超時TimeoutException:" + ex.ToString()); } catch (Exception ex) { (proxy as ICommunicationObject).Close(); WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常Exception:" + ex.ToString()); }
但如果這種代碼遍布整個項目,我想就有重構的必要了,因為項目中最好不要出現類似復制的代碼出現,為此我們可以采用Invoke形式來重構我們已有代碼,下面給出兩個方法,一個是沒有返回值的,一個是有值的。
public static void Invoke<TContract>(TContract proxy, Action<TContract> action) { try { action(proxy); (proxy as ICommunicationObject).Close(); } catch (CommunicationException ex) { (proxy as ICommunicationObject).Abort(); WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常CommunicationException:" + ex.ToString()); } catch (TimeoutException ex) { (proxy as ICommunicationObject).Abort(); WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據超時TimeoutException:" + ex.ToString()); } catch (Exception ex) { (proxy as ICommunicationObject).Close(); WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常Exception:" + ex.ToString()); } } public static TReturn Invoke<TContract, TReturn>(TContract proxy, Func<TContract, TReturn> func) { TReturn returnValue = default(TReturn); try { returnValue = func(proxy); } catch (CommunicationException ex) { (proxy as ICommunicationObject).Abort(); WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常CommunicationException:" + ex.ToString()); } catch (TimeoutException ex) { (proxy as ICommunicationObject).Abort(); WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據超時TimeoutException:" + ex.ToString()); } catch (Exception ex) { WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常Exception:" + ex.ToString()); } return returnValue; }
如何調用:可以看出客戶端代碼已經變成一條簡潔代碼了,它即完成了完整的異常處理,而且也把所有能夠捕獲的異常信息記錄下來。
list = ErrorHandler.Invoke<ISearchHotelForSquare, List<HotelGenericInfo>>(cli, proxy => proxy.GetHotelGenericListForSquare(requestInfo).ToList());
--此文章根據網絡資源整理.純屬個人筆記,別無其它商業用途.