2018/01/18

使用 using IDisposable 物件包裝 Stopwatch 並可自訂 log 處理動作

受到黑暗執行序一篇文章《野人獻曝 - 極簡風格 .NET Stopwatch 計時法》的啟發,我延伸了一點小小的功能,讓寫 log 的動作更有彈性一點。原文使用 IDisposable 物件包裝 Stopwatch,在程式碼中以 using 方式使用,在大括號內自動計時,並且在結束的時候寫出 log 內容。在實作 DIspose() 時示範加入 Console.WriteLine 寫出 log 資訊。但如果使用的情境,不一定是要在 Console 或 log 檔案輸出資訊的話呢? 可能是在視窗畫面上顯示資訊。為了達成這樣的目的,我作了小小的修改,在建構子傳入 Action<Stopwatch> 委派,日後就可以依需求自訂 log 處理動作。

/// <summary>
/// 以 using 方式包裝 Stopwatch 提供監看程式耗時的功能
/// </summary>

public class StopwatchScope : IDisposable {         
    private readonly Stopwatch stopwatch = new Stopwatch();
    private Action<Stopwatch> proc;         

    /// <summary>           
    /// 是否停用           
    /// </summary>
         
    public static bool Disabled { get; set; } = false;

    /// <summary>
    /// 建構式
    /// </summary>

    /// <param name="stopwatchProcess">StopwatchScope dispose 時候要執行的動作</param>
    public StopwatchScope(Action<Stopwatch> stopwatchProcess) {
        if (Disabled) return;
        proc = stopwatchProcess;
        stopwatch.Start();
    }
 
    /// <inheritdoc />
    public void Dispose() {
        if (Disabled) return;
        stopwatch.Stop();
        if (proc != null) proc.Invoke(stopwatch);
    }
}

使用起來大概像這樣,假設我們有個 Logger 物件專門寫 log 檔案,在 using 建立 StopwatchScope 時,可以傳入寫 log 的方法。

using (StopwatchScope sw = new StopwatchScope(w => {Logger.Write("do something 花費秒數: " + w.Elapsed.TotalSeconds.ToString());}) {
    // do something
}

呼叫 Logger 寫檔案,也可以替換成更新 Windows UI 某個 label 的內容或是 status bar 的資訊,如此就可以自訂 log 處理動作。