如何不考虑异常执行列表<Task>中的所有任务

How to execute all Tasks in the List<Task> regardless of exceptions

我的代码如下所示。在每个任务函数中,我传递一个对象的引用,在该对象中可以记录任务中发生的任何异常。我想要的是我的列表中的每个任务都执行,而不管是否发生异常(因为我已经在函数中记录了异常。)所以我想要的是 lobj_CustomFieldsTasks 列表中的所有任务执行任务的数量,无论其中任何一个遇到异常。有什么建议么?

注意:此代码无法复制和工作 - 它是我正在尝试做的事情的总结。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace LANrevTargetBL
{
public class myEventArgs : EventArgs
{
    public eAPIFunction CompletedProcessName { get; set; }
    public List<Exception> AsyncErrors { get; set; }
}


/// <summary>
/// Class for Devices.  Used for Applying and Removing profiles 
/// </summary>
public class DevicesVM
{

    private async Task LoadCustomFieldsAndServerProfiles(myEventArgs pobj_myEventArgs)
    {
        List<Task> lobj_CustomFieldsTasks;
        lobj_CustomFieldsTasks = new List<Task>();

        // The iobj_AllDevices list is defined as a List<Device> where Device is a custom data class I have
        foreach (Device lobj_Device in iobj_AllDevices)
        {
            lobj_CustomFieldsTasks.Add(MakeCustomFieldCall(lobj_Device.ID, pobj_myEventArgs));
        }

        try
        {
            await Task.WhenAll(lobj_CustomFieldsTasks);
        }
        catch (Exception ex)
        {
            pobj_myEventArgs.AsyncErrors.Add(ex);
        }
    }

    private async Task MakeCustomFieldCall(int pi_DeviceID, myEventArgs pobj_myEventArgs1)
    {
        string ls_WorkRoomList;
        Device lobj_Device;
        APICallHelper lobj_APICallHelper;
        CustomFieldMetaData.RootObject lobj_CustomFieldResult;

        try
        {

            lobj_APICallHelper = new APICallHelper();

            var lobj_ReturnTask = await lobj_APICallHelper.MakeAPICall(eAPIFunction.eCustomFields, "", pi_DeviceID.ToString());

            if (lobj_ReturnTask.Exceptions == null)
            {
                if (iobj_AllDevices != null)
                {
                    lobj_Device = (from lobj_FoundItem in iobj_AllDevices
                                   where lobj_FoundItem.ID == pi_DeviceID
                                   select lobj_FoundItem).ElementAt(0);
                }
            }
            else
            {
                foreach (Exception lobj_Exception in lobj_ReturnTask.Exceptions)
                {
                    pobj_myEventArgs1.AsyncErrors.Add(lobj_Exception);
                }
            }

        }
        catch (Exception ex)
        {
            pobj_myEventArgs1.AsyncErrors.Add(ex);
        }
    }
}

}

使用纯 foreach 而不是 Task.WhenAll

foreach (var task in lobj_CustomFieldsTasks)
{
    try { await task; }
    catch (Exception ex) { pobj_myEventArgs.AsyncErrors.Add(ex); }
}

以上是可行的,因为您已经提前创建(启动)了所有任务。 Task.WhenAll 只是 await 完成所有任务的一种便捷方式,带有您不想要的额外 exception/cancellation 逻辑。相比之下, Task.WhenAny 不能那么容易地被替换,但也没有必要,因为它不会抛出异常。

有关详细信息,请参阅 await (C# Reference)

不需要try/catch任何东西。 WaitAll 运行所有任务,并为您汇总任何异常。查看 https://msdn.microsoft.com/en-us/library/dd270695(v=vs.110).aspx 中的示例。

在示例中,所有任务都已执行,当它们完成时抛出 AggregateException。如果你对这些聚合异常不感兴趣,当然可以忽略这个异常。

然后WhenAll function basically already does what you want to do. It runs all the tasks to completion. In case one or multiple of the tasks faulted with a exception, the resulting Task will also enter the faulted state with a AggregateException。一旦完成所有任务,await 将抛出此异常。您可以在 InnerExceptions 属性 中获取您的任务中发生的真正异常。所以它基本上已经按照您尝试的方式收集了异常。

总而言之:您不需要更改任何内容,除了记录您可能需要解压的异常。

你们都说对了。 WhenAll 将完全按照我的意愿行事。我的问题是在我的异常处理程序中实际上抛出了一个异常。我的 AsyncErrors 对象实际上是空的,因此看起来 WhenAll 没有按需要处理异常。感谢大家的意见。