Ein möglicher Ansatz wird mit jeder Aufgabe in einem Token-Passing und Korrelation ermöglichen bei der Bewertung des Ergebnisses:
public static Task<WhenAllWithTokenResult<TToken>> WhenAllWithToken<TToken>(Tuple<Task, TToken>[] tasks)
{
var successfulTasks = new List<Tuple<Task, TToken>>();
var failedTasks = new List<Tuple<Task, TToken>>();
var cancelledTasks = new List<Tuple<Task, TToken>>();
int amountCompleted = 0;
var taskCompletionSource = new TaskCompletionSource<WhenAllWithTokenResult<TToken>>();
// Register ContinueWith callback for each task and add it to the according result list when completed
foreach (var tuple in tasks)
{
var copyOfTuple = tuple;
tuple.Item1.ContinueWith(_ =>
{
if (_.IsFaulted)
{
failedTasks.Add(copyOfTuple);
}
else if (_.IsCanceled)
{
cancelledTasks.Add(copyOfTuple);
}
else if (_.IsCompleted)
{
successfulTasks.Add(copyOfTuple);
}
if (Interlocked.Increment(ref amountCompleted) == tasks.Length)
{
// All tasks finished so let's set the result of this method
taskCompletionSource.SetResult(new WhenAllWithTokenResult<TToken>(successfulTasks, failedTasks, cancelledTasks));
}
});
}
return taskCompletionSource.Task;
}
public class WhenAllWithTokenResult<TToken>
{
public IList<Tuple<Task, TToken>> SuccessfulTasks { get; private set; }
public IList<Tuple<Task, TToken>> FailedTasks { get; private set; }
public IList<Tuple<Task, TToken>> CancelledTasks { get; private set; }
public WhenAllWithTokenResult(IList<Tuple<Task, TToken>> successfulTasks, IList<Tuple<Task, TToken>> failedTasks, IList<Tuple<Task, TToken>> cancelledTasks)
{
CancelledTasks = cancelledTasks;
SuccessfulTasks = successfulTasks;
FailedTasks = failedTasks;
}
}
und dessen Verwendung mag:
WhenAllWithTokenResult<string> result =
await WhenAllWithToken(
new[]
{
Tuple.Create(_someService.Method1(), "Method1"),
Tuple.Create(_someService.Method2(), "Method2"),
Tuple.Create(_someService.Method3(), "Method3"),
Tuple.Create(_someService.Method4(), "Method4")
});
foreach (var item in result.SuccessfulTasks)
{
Console.WriteLine("Successful: {0}", item.Item2);
}
foreach (var item in result.FailedTasks)
{
Console.WriteLine("Failed: {0}", item.Item2);
}
foreach (var item in result.CancelledTasks)
{
Console.WriteLine("Cancelled: {0}", item.Item2);
}
Bitte beachten Sie, 1) Das Token ist ein generisches und nur weitergegeben, um die Korrelation zu ermöglichen. Also, es kann alles sein, was du willst. 2) WhenAllWithToken hat eine andere Semantik als WhenAll: Es gibt eine Aufgabe zurück, die abgeschlossen ist, wenn alle Eingabeaufgaben entweder erfolgreich waren, fehlgeschlagen oder abgebrochen wurden, aber vorher nicht.
Können Sie den Stack-Trace für jede Ausnahme verwenden? Das sollte Ihnen für jeden Fehler zeigen, welche Methode die Ausnahme verursacht hat. – GSkidmore
Wenn ich Ihren Code verwende, kann ich 'innerException.TargetSite.Name' und einige Zeichenfolgenmanipulation verwenden, um den Methodennamen zu erhalten, wenn Sie das suchen. Für mich hat ein Methodenname Method1 eine TargetSite.Name von ' b__2_0' –