gpt4 book ai didi

c# - C# 中的 Task 和 TaskContinuationOptions 说明?

转载 作者:太空狗 更新时间:2023-10-29 18:32:11 27 4
gpt4 key购买 nike

我有这个简单的代码:

var g=  Task.Factory.StartNew<int> (() => 8)
.ContinueWith (ant =>{throw null;})
.ContinueWith (a =>{ Console.WriteLine("OK");},TaskContinuationOptions.NotOnFaulted);

try{
Console.WriteLine("1");
g.Wait();
Console.WriteLine("2");
}

catch (AggregateException ex)
{Console.WriteLine("catch"); }

输出:

1
catch
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

MSDN :

TaskContinuationOptions.NotOnFaulted

Specifies that the continuation task should not be scheduled if its antecedent threw an unhandled exception. This option is not valid for multi-task continuations.

好的。

enter image description here

没关系 - 不显示这一行会导致上一行 DID 抛出异常。

问题:

  • 我得到 AggregateException 异常是因为我没有检查 Exception 属性吗?

  • 我是否必须始终检查先行词是否抛出异常(在每一行中?)? (我无法检查每一行!这没有任何意义而且很烦人)

  • try catch block 不应该吞下异常吗? (我认为所有异常都会冒泡到 wait 方法....所以?)

最佳答案

Do I get the AggregateException exception because I haven't inspected the Exception property ?

不,你会得到一个异常,因为任务 g 被 TPL 取消了(因为,正如 msdn 所述,如果前面的任务抛出异常,这个任务将不会被安排)。

我们这里有 3 个任务:

  1. 原始任务(使用 StartNew)
  2. 第一个延续任务(抛出异常)
  3. 第二个继续任务(打印 OK)(这是您代码中的 g 任务)。

问题是您要求 TPL 启动 3d 任务仅当第二个任务成功完成时。这意味着如果不满足此条件,TPL 将完全取消您新创建的任务。

你得到了未观察到的任务异常,因为你有你从未观察到的临时任务(我列表中的任务 2)。因为您永远不会观察到它的故障状态,所以它会抛出终结器来告诉您。

您可以通过在 catch block 中打印任务状态来检查这一点:

catch (AggregateException ex)
{
Console.WriteLine("catch");
// Will print: Status in catch: Canceled
Console.WriteLine("Status in catch: {0}", g.Status);
}

Must I always inspect if the antecedent throw an exception ( in each line ? ) ? ( I can't check each line ! it doesn't make any sense and very annoying)

是的,您应该观察先行任务异常以避免此问题:

static class TaskEx
{
public static Task ObserverExceptions(this Task task)
{
task.ContinueWith(t => { var ignore = t.Exception; },
TaskContinuationOptions.OnlyOnFaulted);
return task;
}
}

然后按如下方式使用它:

var g=  Task.Factory.StartNew<int> (() => 8)
.ContinueWith (ant =>{throw null;})
.ObserveExceptions()
.ContinueWith (a =>{ Console.WriteLine("OK");});

try{
Console.WriteLine("1");
g.Wait();
Console.WriteLine("2");
}

catch (AggregateException ex)
{Console.WriteLine("catch"); }

更新:添加了对最后一个项目符号的解决方案

Wasn't the try catch block should have swallow the exception ? ( I thought that all exceptions bubble up to the wait method....so ? )

我们的项目中有一组扩展方法(称为TransformWith)可以解决这个特定问题并获得以下结果:

  1. 异常会冒泡到 catch block 并且
  2. 我们不会因 TaskUnobservedException 而导致应用程序崩溃

这里是用法

var g = Task.Factory.StartNew(() => 8)
.ContinueWith(ant => { throw null; })
// Using our extension method instead of simple ContinueWith
.TransformWith(t => Console.WriteLine("OK"));

try
{
Console.WriteLine("1");
// Will fail with NullReferenceException (inside AggregateExcpetion)
g.Wait();
Console.WriteLine("2");
}

catch (AggregateException ex)
{
// ex.InnerException is a NullReferenceException
Console.WriteLine(ex.InnerException);
}

这是一个扩展方法:

static class TaskEx
{
public static Task TransformWith(this Task future, Action<Task> continuation)
{
var tcs = new TaskCompletionSource<object>();
future
.ContinueWith(t =>
{
if (t.IsCanceled)
{
tcs.SetCanceled();
}
else if (t.IsFaulted)
{
tcs.SetException(t.Exception.InnerExceptions);
}
else
{
try
{
continuation(future);
tcs.SetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
}
}, TaskContinuationOptions.ExecuteSynchronously);

return tcs.Task;
}
}

关于c# - C# 中的 Task<T> 和 TaskContinuationOptions 说明?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13739793/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com