gpt4 book ai didi

c# - 使用 Task.IsFaulted 表示 IO 故障而不传播异常

转载 作者:行者123 更新时间:2023-11-30 15:23:35 24 4
gpt4 key购买 nike

之前/没有 Task<> s,我正在使用如下所示的包装器对象来封装可能失败的 I/O 操作的结果,而不会将异常传播到调用堆栈中:

public class FetchResult<T>
{
public readonly bool Success;
public readonly T Item;

public FetchResult(bool success, T item)
{
this.Success = success;
this.Item = item;
}
}

我会这样使用它:

var userResult = Get("robert.paulson@fightclub.com");
if(!userResult.Success)
// abort, or something

...

public FetchResult<User> Get(string email)
{
try
{
// go to database here, and get the User
return new FetchResult(true, new User());
}
catch
{
// log exception
return new FetchResult(false, null);
}
}

作为一个模型,这对我来说非常有用,因为它允许我在不使用 try/catch 的情况下有效地管理异常。作为程序控制流,并为我提供简单且细粒度的优雅服务降级。

但是,随着 Task<> 的出现,我很容易得到:

    public Task<FetchResult<User>> GetAsync(string email)

这似乎已经失控了。看到我正在迁移到 async无论如何,我正在考虑这样做:

    public Task<User> GetAsync(string email)

哪个 id 期望允许我做类似的事情:

var userTask = GetAsync("robert.paulson@fightclub.com");
await userTask;
if(userTask.IsFaulted) // (*) - see below
// abort, or something

但是如果我的GetAsync方法返回:

return Task<User>.FromException(new Exception());

等待后实际返回的内容((*) 注释所在的位置)似乎是已完成的 Task , 谁的结果是 Task<User>这是错误的。

为什么在这种情况下我会得到一个嵌套任务,我是否缺少一些语法糖来让整个事情更整洁?

最佳答案

任务库中有两个方法FromException()FromException<TResult>()两者都可以通过 Task 获得和 Task<TResult> .

public static Task FromException(Exception exception)
{
return FromException<VoidTaskResult>(exception);
}

public static Task<TResult> FromException<TResult>(Exception exception)
{
...
...
}

如果您调用 Task<TResult>.FromException()Task.FromException()这两个电话没有什么不同。

您的方法签名是:public Task<User> GetAsync(string email)现在,如果您尝试使用 Task<User>.FromException(new Exception())这将返回 Task<VoidTaskResult>这当然不是 Task<User> 类型.这意味着您可能遇到编译器错误。

如果你使用 Task<User>.FromException<User>(new Exception());,这个编译时错误就会消失或 Task.FromException<User>(new Exception());

你得到 Task<Task<VoidTaskResult>>如评论中所指定,意味着您的方法代码中还有更多内容在您的示例代码中未提及。

有关 Task 的更多内部详细信息.Net 源代码中的方法参见 here

更新:

在查看您的代码后发现了几个问题。

i) 作为任务的返回类型避免了我之前在回答中提到的编译错误。

ii) 你在 Async 方法中返回一个 Task 而不等待意味着完整的任务对象将被包装在另一个 Task 类型中。

请参阅下面我调整以显示问题的示例。看到即使返回类型从对象类型的任务更改为程序,仍然没有错误。这是因为 Object 是 C# 中任何自定义类型的基础。所以允许执行以下操作:

static async Task<object> GetAsync()
{
try
{
throw new Exception();
}
catch (Exception e)
{
return Task.FromException<Program>(e);
}
}

现在将方法的返回类型更改为Task<Program>你会得到一个错误或更多的警告。 Warning   CS1998  This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

现在解决问题的正确版本是等待任务,这样只有程序类型保留为结果,它将自动返回为 Task<Program> .

正确的版本:

 static async Task<Program> GetAsync()
{
try
{
throw new Exception();
}
catch (Exception e)
{
return await Task.FromException<Program>(e);
}
}

现在您将不会再看到任何嵌套任务。这是 await 工作原理的内部结构。如果你真的想知道为什么会这样,那么尝试使用 IL spy 分析所有上述 3 个版本的程序生成的 IL,你就会明白了。干杯!!!

关于c# - 使用 Task<T>.IsFaulted 表示 IO 故障而不传播异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34299796/

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