簡體   English   中英

C#事件異常未在父方法中捕獲

[英]C# event exception not caught in parent method

我正在努力實現緩存的get方法。 如果已超過最大等待時間(在我的情況下為100ms用於測試),則此方法將返回給調用方。

我的問題是,在計時器觸發事件​​之后,永遠不會到達異常。

請幫我理解為什么? 我讀到事件是在同一線程上執行的,所以這不是問題

public static T Get<T>(string key, int? maxMilisecondsForResponse = null)
{
        var result = default(T);

        try
        {
            // Return default if time expired
            if (maxMilisecondsForResponse.HasValue)
            {
                var timer = new System.Timers.Timer(maxMilisecondsForResponse.Value);
                timer.Elapsed += OnTimerElapsed;
                timer.AutoReset = false;
                timer.Enabled = true;   // start the timer
            }

            var externalCache = new CacheServiceClient(BindingName);

            Thread.Sleep(3000);  // just for testing
        }
        catch (Exception ex)   
        {
            // why is the exception not caught here?
        }

        return result;
}

private static void OnTimerElapsed(object source, System.Timers.ElapsedEventArgs e)
{
    throw new Exception("Timer elapsed");
}

MSDN

Timer組件捕獲並抑制事件處理程序為Elapsed事件拋出的所有異常。 在將來的.NET Framework版本中,此行為可能會更改。

並繼續

但是請注意,對於異步執行並包括await運算符(在C#中)或Await運算符(在Visual Basic中)的事件處理程序,情況並非如此。 這些事件處理程序中引發的異常將傳播回調用線程。

請看一下異常處理(任務並行庫)

下面是一個應用示例:

public class Program
{
    static void Main()
    {
        Console.WriteLine("Begin");
        Get<string>("key", 1000);
        Console.WriteLine("End");
    }

    public static T Get<T>(string key, int? maxMilisecondsForResponse = null)
    {
        var result = default(T);

        try
        {
            var task = Task.Run(async () =>
            {
                await Task.Delay(maxMilisecondsForResponse.Value);
                throw new Exception("Timer elapsed");
            });
            task.Wait();
        }
        catch (Exception ex)   
        {
            // why the exception is not catched here?
            Console.WriteLine(ex);
        }

        return result;
    }
}

計時器在其自己的線程上觸發。 您可以在此答案中了解更多信息。

您問題的答案是使用可以取消的異步方法。 然后,您可以使用取消令牌源並以正確的方式進行操作,而不是使用計時器自行制作解決方案。

您可以在此處找到良好的概述。

例如:

cts = new CancellationTokenSource();  

cts.CancelAfter(2500);  

await Task.Delay(10000, cts.Token);

這將取消2500(共10000個)之后的等待任務,因為它花費的時間太長。 顯然,您需要在任務中插入自己的邏輯,而不僅僅是等待。

timer正在自己的線程中執行,但是您無法在調用者級別捕獲異常。 因此,在這種情況下使用計時器不是一個好的方法,您可以通過創建Task操作來更改它。

var result = default(T);
CacheServiceClient externalCache;
if (!Task.Run(() =>
{
    externalCache = new CacheServiceClient(BindingName);
    return externalCache;
}).Wait(100))//Wait for the 100 ms to complete operation.
{
    throw new Exception("Task is not completed !");
}
// Do something
return result;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM