避免异步空闲的原因,是否可以从调用代码中捕获以下错误?
private static Action ErrorAction { get { return async () => { await Task.Delay(0); throw new NotImplementedException(); }; } }
例如,在以下两个中我想收集抛出的异常,但两个测试都失败了:
[Test] public void SelfContainedExampleTryCatch() { List<Exception> errors = new List<Exception>(); try { ErrorAction(); } catch (Exception ex) { errors.Add(ex); } errors.Count().Should().Be(1); } [Test] public void SelfContainedExampleContinueWith() { List<Exception> errors = new List<Exception>(); var task = Task.Factory.StartNew(ErrorAction); task.ContinueWith(t => { errors.Add(t.Exception); },TaskContinuationoptions.OnlyOnFaulted); task.Wait(); errors.Count().Should().Be(1); }
我知道我可以使用带有异步任务签名的方法;但具体来说,它是我需要处理的Action可分配代理异步代码示例,并且在全局级别捕获是不切实际的.如果可能的话,同步和异步动作共同的解决方案将是理想的.
希望有一个我错过的简单解决方案,但到目前为止,我只是走了许多死胡同并且(可能不正确)得出结论它是不可能的.任何帮助(或浪费时间)将不胜感激!
解决方法
在某些情况下,框架要求您使用异步void,有时您真的不愿意(例如,ICommand.Execute).在这些情况下,我通常建议引入一个与await兼容的API,并使你的异步void方法非常简单的包装器:
static Func<Task> ErrorActionAsync { get { return async () => { await Task.Yield(); throw new NotImplementedException(); }; } } private static Action ErrorAction { get { return async () => { await ErrorActionAsync(); } } }
(在旁注中,我更改了等待Task.Delay(0)以等待Task.Yield(),因为等待Task.Delay(0)是noop).
然后,您可以在单元测试中使用ErrorActionAsync而不是ErrorAction.这种方法确实意味着您将拥有少量未经测试的代码(异步void包装器 – ErrorAction).
但是,如果您希望将ErrorAction保持原样,并且它可以是同步的或异步的,那么还有另一种可能性.我写了一个你可以这样使用的AsyncContext
type:
[Test] public void SelfContainedExampleTryCatch() { List<Exception> errors = new List<Exception>(); try { AsyncContext.Run(() => ErrorAction()); } catch (Exception ex) { errors.Add(ex); } errors.Count().Should().Be(1); }
AsyncContext.Run将阻塞,直到async void方法完成,并将从异步void方法捕获异常并直接引发它们.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。