c#事件异常未在父方法中捕获



im正在努力实现缓存的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");
}

计时器在其自己的线程上触发。您可以在此答案中阅读有关它的更多信息。

您问题的答案是使用可以取消的异步方法。然后,您可以使用取消令牌源,并以适当的方式执行此操作,而不是用计时器对解决方案进行自制解决方案。

您可以在这里找到一个很好的概述。

例如:

cts = new CancellationTokenSource();  
cts.CancelAfter(2500);  
await Task.Delay(10000, cts.Token);

这将在2500(of 10000)之后取消等待任务,因为花了太长时间。显然,您需要在任务中插入自己的逻辑,而不仅仅是等待。

来自msdn

计时器组件捕获并抑制所有异常。 经过的事件的活动处理程序。这种行为受 更改.NET框架的未来版本。

并继续

请注意,执行的事件处理程序不是正确的 异步并包括等待运营商(在C#中)或等待 操作员(在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;
    }
}

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;

最新更新