首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

泛型委派在專案中的實戰應用:封裝 WCF 客戶端異常處理

     編輯:關於.NET

Action<T>、Func<T, TResult> 等泛型委派是 .NET 2.0 引入的強大工具,能以類型安全方式傳遞程式碼塊,避免重複撰寫委派類型。本文展示如何利用泛型委派重構遍佈專案的 WCF 客戶端異常處理樣板碼,實現「一次定義,處處復用」。

一、痛點:到處都是重複的 try-catch

呼叫 WCF 服務時,必須處理 CommunicationException、TimeoutException 並正確關閉/中止通道:

try
{
    // 呼叫服務
    var result = proxy.GetData(request);
    (proxy as ICommunicationObject).Close();
}
catch (CommunicationException ex)
{
    (proxy as ICommunicationObject).Abort();
    Logger.Error("CommunicationException: " + ex);
}
catch (TimeoutException ex)
{
    (proxy as ICommunicationObject).Abort();
    Logger.Error("TimeoutException: " + ex);
}
catch (Exception ex)
{
    (proxy as ICommunicationObject).Close();
    Logger.Error("Exception: " + ex);
}

專案中有數十個服務呼叫點,複製貼上導致維護噩夢。

二、重構:泛型委派統一異常處理

定義兩個靜態輔助方法,分別處理無回傳值與有回傳值的服務呼叫:


public static class WcfInvokeHelper
{
    /// 無回傳值服務呼叫
    public static void Invoke<TContract>(TContract proxy, Action<TContract> action)
        where TContract : class
    {
        try
        {
            action(proxy);
            (proxy as ICommunicationObject).Close();
        }
        catch (CommunicationException ex)
        {
            (proxy as ICommunicationObject).Abort();
            LogError("CommunicationException", ex);
        }
        catch (TimeoutException ex)
        {
            (proxy as ICommunicationObject).Abort();
            LogError("TimeoutException", ex);
        }
        catch (Exception ex)
        {
            (proxy as ICommunicationObject).Close();
            LogError("Exception", ex);
        }
    }

    /// 有回傳值服務呼叫
    public static TReturn Invoke<TContract, TReturn>(TContract proxy, Func<TContract, TReturn> func)
        where TContract : class
    {
        TReturn result = default;
        try
        {
            result = func(proxy);
            (proxy as ICommunicationObject).Close();
        }
        catch (CommunicationException ex)
        {
            (proxy as ICommunicationObject).Abort();
            LogError("CommunicationException", ex);
        }
        catch (TimeoutException ex)
        {
            (proxy as ICommunicationObject).Abort();
            LogError("TimeoutException", ex);
        }
        catch (Exception ex)
        {
            (proxy as ICommunicationObject).Close();
            LogError("Exception", ex);
        }
        return result;
    }
    private static void LogError(string prefix, Exception ex)
    {
        // 實際專案使用 log4net/NLog 等
        Console.WriteLine($"[{prefix}] {ex}");
    }
}

三、呼叫端極簡化

無回傳值:

WcfInvokeHelper.Invoke<IOrderService>(proxy, p => p.SubmitOrder(orderDto));

有回傳值:


var hotels = WcfInvokeHelper.Invoke<IHotelSearch, List<HotelInfo>>(
    proxy, p => p.SearchHotels(criteria).ToList());

Lambda 運算式直接內嵌業務邏輯,異常處理、通道管理完全內聚於輔助方法。

四、原理對比:自訂委派 vs 泛型委派


// 傳統:每種簽名都要聲明委派類型
delegate void DisplayMessage(string msg);
delegate TResult Calculate<T1, T2, TResult>(T1 a, T2 b);

// 泛型委派:框架內建,開箱即用
Action<string> act = Console.WriteLine;
Func<int, int, int> add = (a, b) => a + b;

Action<T1...T4> 對應無回傳值方法,Func<T1...T4, TResult> 對應有回傳值方法,最多支援 16 個參數(.NET 4.0+),完全覆蓋實際需求。

五、延伸:RealProxy 與 AOP

.NET Remoting 的 RealProxy 核心方法 IMessage Invoke(IMessage msg) 同樣是攔截呼叫的統一入口,但缺乏泛型委派的類型安全與語法便利。現代專案推薦使用 Castle DynamicProxy、PostSharp 或 .NET Core 內建 DispatchProxy 實現 AOP,配合泛型委派處理橫切關注點(日誌、交易、重試、快取)。

結語

泛型委派不是高深理論,而是消除樣板碼、提升程式碼表達力的利器。下次看到重複的 try-catch、using、鎖定、重試邏輯,請嘗試用 Action/Func 封裝成可復用的輔助方法——程式碼會變得更乾淨、更安全、更易維護。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved