程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 泛型委托在項目中的應用

泛型委托在項目中的應用

編輯:關於.NET

感悟:對泛型委托基本屬於有點認識,但從來沒真正在項目中使用過,有時感覺沒有合適的場景應用,但看了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()); 

說明:至於Invoke的應用,在System .Runtime .Remoting.Proxies有一個RealProxy,可以稱做真正代理,裡面有IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)方法:只不過這裡面沒有應用泛型委托。

// 返回結果:
//     The message returned by the invoked method, containing the return value and
//     any out or ref parameters.
public abstract IMessage Invoke(IMessage msg);

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved