我正在为缓存实现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");
}
答案 0 :(得分:2)
来自MSDN
Timer组件捕获并抑制所引发的所有异常 Elapsed事件的事件处理程序。此行为受制于 在.NET Framework的未来版本中进行更改。
并继续
但请注意,执行的事件处理程序不是这样 异步并包含await运算符(在C#中)或Await 运算符(在Visual Basic中)。这些事件处理程序中抛出异常 传播回调用线程。
请查看Exception Handling (Task Parallel Library)
以下应用示例:
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;
}
}
答案 1 :(得分:2)
计时器触发它自己的线程。您可以在this answer中了解有关它的更多信息。
您的问题的答案是使用可以取消的异步方法。然后,您可以使用取消令牌源并以正确的方式执行此操作,而不是使用计时器自行创建解决方案。
您可以找到一个好的概述here。
例如:
cts = new CancellationTokenSource();
cts.CancelAfter(2500);
await Task.Delay(10000, cts.Token);
这将取消2500(10000)之后的等待任务,因为它花了太长时间。显然,您需要在任务中插入自己的逻辑而不是等待。
答案 2 :(得分:0)
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;