Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ContinueWith和TaskCancellation-如果任务失败,如何返回默认值?_C#_Task Parallel Library_Task - Fatal编程技术网

C# ContinueWith和TaskCancellation-如果任务失败,如何返回默认值?

C# ContinueWith和TaskCancellation-如果任务失败,如何返回默认值?,c#,task-parallel-library,task,C#,Task Parallel Library,Task,我读了一些关于任务取消的帖子。。但是,对于一个简单的问题,我找不到解决方案:当我的任务失败时,如何获得默认值 我不能(!)修改任务本身并在其周围放置try-catch包装。我当然可以尝试一下等待,但如果可能的话,我想用ContinueWith-来处理这个问题 public Task<List<string>> LoadExample() { Task<List<string>> task = LoadMyExampleTask();

我读了一些关于任务取消的帖子。。但是,对于一个简单的问题,我找不到解决方案:当我的任务失败时,如何获得默认值

我不能(!)修改任务本身并在其周围放置try-catch包装。我当然可以尝试一下等待,但如果可能的话,我想用
ContinueWith
-来处理这个问题

public Task<List<string>> LoadExample()
{
    Task<List<string>> task = LoadMyExampleTask();
    task.ContinueWith(t => default(List<string>), TaskContinuationOptions.OnlyOnFaulted);
    return task;
}
根据Luaan的精彩回答,我编写了一个带有defaultValue选项的扩展方法:

public static Task<T> DefaultIfFaulted<T>(this Task<T> @this, T defaultValue = default(T))
{
   return @this.ContinueWith(t => t.IsCompleted ? t.Result : defaultValue);
}
公共静态任务defaultiffault(此任务@this,T defaultValue=default(T))
{
返回@this.ContinueWith(t=>t.IsCompleted?t.Result:defaultValue);
}
编辑:
等待我的任务。defaultiffault()
刚刚抛出一个

[错误]致命的未处理异常:System.AggregateException


您确定捕获到了所有异常吗?

如果需要,您不能返回原始任务-您需要返回延续

public Task<List<string>> LoadExample()
{
    Task<List<string>> task = LoadMyExampleTask();
    return task.ContinueWith(t => 
            t.IsFaulted || t.IsCanceled ? default(List<string>) : t.Result);
}

正如所承诺的,以下是符合其名称(以及此问题的标题)的
defaultifaulted
变体。它们保留先行任务的行为,除非它出现故障(特别是,取消被传播,而不是被忽略或被
聚合异常
掩盖):

旧式(.NET 4.0)方式:

测试(通过上述所有测试):

使用Xunit;
[事实]
公共异步任务DefaultIfFaultedTest()
{
var success=Task.Run(()=>42);
var faulted=Task.Run(new Func(()=>{throw new invalidooperationexception();}));
Assert.Equal(42,wait success.defaultiffault());
Assert.Equal(0,wait faulted.DefaultIfFaulted());
等待Assert.ThrowsAsync(()=>
{
var tcs=new TaskCompletionSource();
setCancelled();
返回tcs.Task.defaultiffault();
});
}

默认值(列表)
null
<代码>默认值运算符不适用于您已经知道需要引用类型的默认值的情况…@MatíasFidemraizer不适用<代码>默认值(列表)是一个类型空值-它允许类型推断正确工作,在这种情况下,确保从
ContinueWith
返回的任务是
任务
。真的,我现在很少使用literal
null
。当然,这取决于他是否真的想要空值,或者说,
newlist()
@Luaan在我的情况下,我使用
default
,就在实际需要的时候
我当然可以尝试一下,但如果可能的话,我想用ContinueWith来处理这个问题。
-你到底为什么要用艰难的方式而不是简单的方式来做呢???这就像问“我想要一个WebSocket服务器。我当然可以使用Signal,但如果可能的话,我想用TCP套接字类来处理这个问题。”Stephen,我想用“最漂亮”的方式来实现它,并尝试catch对我来说似乎过时了;)此外,我想隐藏信息,因为人们可能忘记实现try-catch-around-wait;),它可能会抛出异常简直太神奇了。谢谢你的快速回答我会尽快标记它。
IsCompleted
的规范如下所示:当任务处于最后三种状态之一时,IsCompleted将返回true:RanToCompletion、Faulted或Canceled。看到问题了吗?三分之二的状态将导致
Result
access异常。我也会用
TaskContinuationsOptions.executes同步执行
来安排继续,但那只是我自己。@KirillShlenskiy-Doh,我的错。我最初使用的
IsFaulted
,但我不想忽略取消。已修复。@Frame91正如Kirill所指出的,我犯了一个错误-
IsCompleted
即使在任务出错时也将返回true。试试固定版本吧。是的,我有点不确定取消时会发生什么。这一点从未具体说明。我将在几分钟内给出一个完全保留取消语义的答案——如果只是作为一个学术练习的话。谢谢!我喜欢你最后的方法。到目前为止,它工作正常:)
public Task<List<string>> LoadExample()
{
    Task<List<string>> task = LoadMyExampleTask();
    return task.ContinueWith(t => 
            t.IsFaulted || t.IsCanceled ? default(List<string>) : t.Result);
}
public static Task<T> DefaultIfFaulted<T>(this Task<T> @this)
{
  return @this.ContinueWith (t => t.IsCanceled || t.IsFaulted ? default(T) : t.Result);
}
public static Task<T> DefaultIfFaulted<T>(this Task<T> task)
{
    // The continuation simply returns the antecedent task unless it's faulted.
    Task<Task<T>> continuation = task.ContinueWith(
        t => (t.Status == TaskStatus.Faulted) ? Task.FromResult(default(T)) : t,
        TaskContinuationOptions.ExecuteSynchronously
    );

    return continuation.Unwrap();
}
public static async Task<T> DefaultIfFaulted<T>(this Task<T> task)
{
    try
    {
        return await task.ConfigureAwait(false);
    }
    catch (Exception ex) when (!(ex is OperationCanceledException))
    {
        return default(T);
    }
}
public static async Task<T> DefaultIfFaulted<T>(this Task<T> task)
{
    // Await completion regardless of resulting Status (alternatively you can use try/catch).
    await task
        .ContinueWith(_ => { }, TaskContinuationOptions.ExecuteSynchronously)
        .ConfigureAwait(false);

    return task.Status != TaskStatus.Faulted
        // This await preserves the task's behaviour
        // in all cases other than faulted.
        ? await task.ConfigureAwait(continueOnCapturedContext: false)
        : default(T);
}
using Xunit;

[Fact]
public async Task DefaultIfFaultedTest()
{
    var success = Task.Run(() => 42);
    var faulted = Task.Run(new Func<int>(() => { throw new InvalidOperationException(); }));

    Assert.Equal(42, await success.DefaultIfFaulted());
    Assert.Equal(0, await faulted.DefaultIfFaulted());

    await Assert.ThrowsAsync<TaskCanceledException>(() =>
    {
        var tcs = new TaskCompletionSource<int>();

        tcs.SetCanceled();

        return tcs.Task.DefaultIfFaulted();
    });
}