C# 如何检索ValueTask的异常?

C# 如何检索ValueTask的异常?,c#,async-await,task,C#,Async Await,Task,即将推出的C#8的设计使用ValueTask和ValueTask将潜在的同步结果传回消费者逻辑。它们都有IsFaulted属性,但与任务不同的是,没有异常属性 甚至可能有一个ValueTask无法保存正常的任务,并且处于故障或取消状态 ValueTask.Result的文档表明,在失败的任务上调用它将重新显示包含的异常。因此,以下代码提取异常是否有意义 IAsyncEnumerable asyncSequence=。。。 ValueTask ValueTask=asyncSequence.Mov

即将推出的C#8的设计使用
ValueTask
ValueTask
将潜在的同步结果传回消费者逻辑。它们都有
IsFaulted
属性,但与
任务
不同的是,没有
异常
属性

甚至可能有一个
ValueTask
无法保存正常的
任务,并且处于故障或取消状态

ValueTask.Result
的文档表明,在失败的任务上调用它将重新显示包含的
异常。因此,以下代码提取
异常是否有意义

IAsyncEnumerable asyncSequence=。。。
ValueTask ValueTask=asyncSequence.MoveNextAsync();
if(valueTask.IsFaulted){
//这必须在非异步方法中工作
//没有理由在此处阻止或使用
//异步关键字
试一试{
var x=valueTask.Result;
}捕获(例外情况除外){
//例外情况下工作
}
}
ValueTask endTask=asyncSequence.DisposeAsync();
if(endTask.IsFaulted){
//没有ValueTask.Result属性
//因此,上述方法不起作用
}
非通用的
ValueTask
没有
Result
属性。那么如何提取
异常


一般来说,我认为应用
AsTask
可以用于两种提取,但是,据我所知,我认为这会导致分配,使得
ValueTask
的使用在一开始就有问题。

你最好的选择是使用try语句,尝试捕获异常,然后稍后再处理它。。。 关于不包含正常任务的ValueTask,我认为您可以使用lambda方法来解决这个问题

try {
    var x = Task.Run(()=>{ ... });
}
catch (Exception ex) {
    // Do something with exception.
}
或者不管ValueTask的情况如何。考虑到C#在过去的构建中一直关注异步任务,可以肯定地说,您将使用lambda和事件调用

private void foo(ValueTask task) {
        lock (threadObj) {
            var x = Task.Run(()=> { return task.doWork(); }
            if (x == true) {
                // then do other work...
            }
            else {
                // handle 'exception'...
            }
        }
}

任务
任务
完成之前进行阻止的常用方法是调用

如果抛出异常,它将是一个异常。将具有导致当前异常的异常集合

从.NET Framework 4.5和.NET Core 1.0开始,您还可以在其中对其返回值调用
GetResult()
,并在集合中引发第一个异常

但你永远不应该这样做

您应该这样做:

// this has to work in a non-async method
try {
    var x = await valueTask;
} catch (Exception ex) {
    // work with the exception
}
ValueTask
ValueTask
用于在结果可能已经可用时避免堆分配。这并不意味着阻止该任务是安全的。

的响应表明这确实不可能直接实现,并且由于需要更改配套界面而无法轻松添加,这将带来复杂性

正如我最初猜测的那样,解决方案建议使用
AsTask
获取
异常

IAsyncEnumerable asyncSequence=。。。
ValueTask ValueTask=asyncSequence.MoveNextAsync();
if(valueTask.IsFaulted){
var ex=valueTask.AsTask().Exception;
//例外情况下工作
}
ValueTask endTask=asyncSequence.DisposeAsync();
if(endTask.IsFaulted){
var ex=valueTask.AsTask().Exception;
//例外情况下工作
}

这个答案对我来说毫无意义。首先,我有一个通过第三方方法返回给我的
ValueTask
。另外,关于
ValueTask
,您指的是什么“lambdas”和“事件调用”?很抱歉,我说得不太清楚。但本质上,lambda是封装在括号和括号中的方法。ie foo(对象发送方,EventArgs e)等于(s,e)=>{…},事件调用正在利用事件并调用它们。ie someEvent?.Invoke((s,e)=>{…})此示例使用lambads和事件调用调用调用方法作为参数。。。这种编程通常在System.Linq中使用。因此,我想说的是,一旦你有了valueTask,你就可以在线程安全的环境中使用它,这可以让你捕获程序所表达的不想要的动作。我的问题与lambdas或创建任务无关。我已经有一个
ValueTask
来自我无法控制的地方,必须从中获取
异常
。您使用
.Result
而不是
async
/
wait
有什么原因吗?您确实知道(取决于您的上下文),这是基于您的注释的上述内容的可能重复
这必须在非异步方法中工作
这似乎是您的根本问题,但如果没有更多上下文,则很难判断是否存在异常无法从
IValueTaskSource
,因此,从这里我看到了两种方法:要么
.AsTask().Exception
要么
.GetAwaiter().GetResult()
捕获异常。令人惊讶的是,
AsTask()
实际上让底层的
IValueTaskSource
抛出异常,捕获它,并从中创建一个错误的任务:起初我很困惑,没有一个更优化的路径,但最终异常的代价是如此高昂,以至于一旦你得到了一个异常,你就不应该再关心微优化了。发布它:首先,我必须使用
ValueTask
,其中
IsFaulted
is
true
,因此我不必为任何事情而阻塞。第二个似乎是分配的,因此我不太可能比使用
AsTask
更好。第三,提取应该在没有
wait
的情况下工作,因为父方法不是,也不能标记为
async
。如果不能使用
async
,请坚持使用
IEnumerable
。可能我不清楚,但使用
ValueTask
是必须的。我无法更改为
IEnumerable
,因为它对我的情况没有语义意义,而且不可能,因为我尝试与之交互的API不是def