C# 并行异常处理。在任务内部调用

C# 并行异常处理。在任务内部调用,c#,task-parallel-library,C#,Task Parallel Library,我有以下代码 var exceptions = new ConcurrentQueue<Exception>(); Task task = Task.Factory.StartNew(() => { try { Parallel.Invoke( async () => await _aViewModel.LoadData(_someId), async () => await _bVie

我有以下代码

var exceptions = new ConcurrentQueue<Exception>();
Task task = Task.Factory.StartNew(() =>
{
    try
    {
        Parallel.Invoke(
            async () => await _aViewModel.LoadData(_someId),
            async () => await _bViewModel.LoadData(_someId)
        );
    }
    catch (Exception ex)
    {
        exceptions.Enqueue(ex);
    }
}).ContinueWith((continuation) =>
    {
        if (exceptions.Count > 0) throw new AggregateException(exceptions);
    });
var exceptions=new ConcurrentQueue();
Task Task=Task.Factory.StartNew(()=>
{
尝试
{
并行调用(
async()=>await\u aViewModel.LoadData(\u someId),
async()=>await\u bViewModel.LoadData(\u someId)
);
}
捕获(例外情况除外)
{
例外情况。排队(ex);
}
}).ContinueWith((continuence)=>
{
如果(exceptions.Count>0)抛出新的AggregateException(异常);
});
我在这里使用Task.StartNew是因为LoadData方法使用Dispatcher.StartAsync方法在主UI线程内部调用


我的问题是,如果我强制
\u aViewModel.LoadData
抛出异常,它不会被Catch(exception)子句捕获(如果我捕获aggregateeexception,也不会被捕获)。我不明白为什么

Parallel.Invoke
接受一组
操作
委托。它无法知道您的委托实际上是
async
方法,因此它会在任务完成之前返回

要深入解释这种行为,请关注该主题

尝试更改您的代码以使用


Parallel.Invoke
不支持
async
。因此,您的
async
lambda正在被转换为
async void
方法,这些方法具有极其笨拙的错误语义(不允许它们离开
async void
方法;相反,它们被捕获并直接在
SynchronizationContext
上重新引发,该上下文在
async void
方法启动时处于活动状态-在本例中为线程池)

我不知道为什么您首先要使用
并行.Invoke
。因为您的方法已经是
async
,所以您可以这样做:

Task task = Task.Factory.StartNew(async () =>
{
    try
    {
        Task.WaitAll(
            _aViewModel.LoadData(_someId),
            _bViewModel.LoadData(_someId)
        );
    }
    catch (Exception ex)
    {
        exceptions.Enqueue(ex);
    }
})...

另外,如果您有时间,请重新考虑这部分代码的结构。
Dispatcher.StartAsync
是一种代码味道。UI应该是(异步的)请求数据;数据检索对象不必知道UI。

我当前使用Dispatcher.StartAsync的原因是LoadData方法从web服务获取数据,并加载到ObservableCollections中,除非调用回主线程。处理所有数据绑定对象/ViewMoDEL(例如,
可观察集合
)作为“逻辑UI”。然后,“逻辑UI”应该从(异步)请求数据方法返回,而不是将其设置为副作用。透视图中的更改将有助于清理代码。我无法完全获得从LoadData方法返回IEnumerable的语法。它们返回任务,但使用
var data=\u aViewModel.LoadData(\u someId)
不编译。@ColinDesmond:您使用
wait
打开
任务
。因此,如果
LoadDataAsync
返回
Task
,那么如果
wait
该任务,您将得到一个
IEnumerable
。如下所示:
IEnumerable data=\u aViewModel.LoadDataAsync(\u someId)
。您可以找到我的。
Task task = Task.Factory.StartNew(async () =>
{
    try
    {
        Task.WaitAll(
            _aViewModel.LoadData(_someId),
            _bViewModel.LoadData(_someId)
        );
    }
    catch (Exception ex)
    {
        exceptions.Enqueue(ex);
    }
})...