简体   繁体   English

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

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

I`m working on implementing a get method for cache. 我正在努力实现缓存的get方法。 This method will return to caller if a maximum wait time has passed(in my case 100ms for tests). 如果已超过最大等待时间(在我的情况下为100ms用于测试),则此方法将返回给调用方。

My issue is that the exception NEVER reaches the catch, after the timer triggered the event. 我的问题是,在计时器触发事件​​之后,永远不会到达异常。

Please help me understand why? 请帮我理解为什么? ( I read that events are executed on the same thread, so that should`t be the issue ) 我读到事件是在同一线程上执行的,所以这不是问题

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");
}

From MSDN MSDN

The Timer component catches and suppresses all exceptions thrown by event handlers for the Elapsed event. Timer组件捕获并抑制事件处理程序为Elapsed事件抛出的所有异常。 This behavior is subject to change in future releases of the .NET Framework. 在将来的.NET Framework版本中,此行为可能会更改。

And continues 并继续

Note, however, that this is not true of event handlers that execute asynchronously and include the await operator (in C#) or the Await operator (in Visual Basic). 但是请注意,对于异步执行并包括await运算符(在C#中)或Await运算符(在Visual Basic中)的事件处理程序,情况并非如此。 Exceptions thrown in these event handlers are propagated back to the calling thread. 这些事件处理程序中引发的异常将传播回调用线程。

Please take a look Exception Handling (Task Parallel Library) 请看一下异常处理(任务并行库)

An applied example below: 下面是一个应用示例:

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;
    }
}

The timer fires on it's own thread. 计时器在其自己的线程上触发。 You can read more about it in this answer . 您可以在此答案中了解更多信息。

The answer to your question is to use async methods that can be cancelled. 您问题的答案是使用可以取消的异步方法。 Then you can use a cancellation token source and do it the proper way instead of homebrewing a solution with timers. 然后,您可以使用取消令牌源并以正确的方式进行操作,而不是使用计时器自行制作解决方案。

You can find a good overview here . 您可以在此处找到良好的概述。

For example: 例如:

cts = new CancellationTokenSource();  

cts.CancelAfter(2500);  

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

This would cancel the waiting task after 2500 (of 10000) because it took too long. 这将取消2500(共10000个)之后的等待任务,因为它花费的时间太长。 Obviously you need to insert your own logic in a task instead of just waiting. 显然,您需要在任务中插入自己的逻辑,而不仅仅是等待。

The timer is being executed in the own thread but you can't catch the exception at the caller level. timer正在自己的线程中执行,但是您无法在调用者级别捕获异常。 So, it is not a good approach to use timer in this case and you can change it by creating the Task operation. 因此,在这种情况下使用计时器不是一个好的方法,您可以通过创建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