C# 编译器如何将返回值转换为返回任务<;价值>;在异步方法中?
我设计了以下方法来创建记录C# 编译器如何将返回值转换为返回任务<;价值>;在异步方法中?,c#,.net,asynchronous,.net-core,async-await,C#,.net,Asynchronous,.net Core,Async Await,我设计了以下方法来创建记录 public Task<Guid> NotAwaited() { Account account = new Account(); Context.Accounts.Add(account); Context.SaveChangesAsync(); return new Task<Guid>(() => account.Id); } 我知道,account.Id部分以某种方式转换为任务。我只是不知道怎么做。感觉就像是黑魔
public Task<Guid> NotAwaited()
{
Account account = new Account();
Context.Accounts.Add(account);
Context.SaveChangesAsync();
return new Task<Guid>(() => account.Id);
}
我知道,account.Id
部分以某种方式转换为任务。我只是不知道怎么做。感觉就像是黑魔法(我知道不是)
是否存在隐式转换?还是我仍然不正确地执行异步调用
感觉就像是黑魔法
可能是的
您编写C#代码,然后编译器将其拆分为多个部分一起运行,并创建一个状态机,每当等待的异步任务完成时,该状态机都会“向前移动”。如果调试代码,调试器知道如何在调试器中表示“局部变量”(实际上可能是状态机类型上的实例成员),并映射到原始源代码的行
因此,对于您的情况,代码可能类似于(通过sharplab创建,请参阅):
[AsyncStateMachine(typeof(d__0))]
等待的公共任务()
{
d_u0状态机=默认值(d_u0);
stateMachine.t__builder=AsyncTaskMethodBuilder.Create();
stateMachine.1_uu状态=-1;
AsyncTaskMethodBuilder t\uuuu builder=stateMachine.t\uu builder;
启动(参考状态机);
返回stateMachine.t\u builder.Task;
}
[StructLayout(LayoutKind.Auto)]
[编译生成]
私有结构d__0:IAsyncStateMachine
{
州内公共交通;
公共异步TaskMethodBuilder t_uuBuilder;
私人帐户5__2;
私人任务等待者1;
私有void MoveNext()
{
int num=1___状态;
Guid id;
尝试
{
任务等待者;
如果(num!=0)
{
5__2=新账户();
Context.Accounts.Add(5__2);
waiter=Context.SaveChangesAsync().getwaiter();
如果(!waiter.IsCompleted)
{
num=(1__状态=0);
u___1=等待者;
建造商等待未安全完成(参考等待者,参考此);
返回;
}
}
其他的
{
等待者=u___1;
u__1=默认值(任务等待器);
num=(1__状态=-1);
}
GetResult();
id=5_uuu2.id;
}
捕获(异常)
{
1_uu状态=-2;
设置异常(异常);
返回;
}
1_uu状态=-2;
设置结果(id);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy根据MoveNext中的.override指令生成此显式接口实现
this.MoveNext();
}
[调试程序隐藏]
私有void SetStateMachine(IAsyncStateMachine stateMachine)
{
t_ubuilder.SetStateMachine(stateMachine);
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine状态机)
{
//ILSpy根据SetStateMachine中的.override指令生成此显式接口实现
此.SetStateMachine(stateMachine);
}
}
您可以看到,调用savechangessync()
的一方位于不同于访问Id属性的逻辑分支中。局部变量account
现在是生成的结构上的5_uu2
字段。所使用的标识符名称实际上都不是有效的C#标识符,但在编译到的底层IL语言中有效,上述代码是实际生成的代码的反编译C#ish表示
调用Awaited()
方法将实际创建“隐藏的”d_u0
结构的新实例(在调试模式下,它将是一个类,而不是一个struct
,以支持编辑和继续),并使用异步基础结构的类型连接此状态机并运行它
MoveNext()
在启动状态机时调用,但在每次等待的任务完成时也会调用(作为延续)。您可以看到,最后一部分将结果设置为id
值,这基本上是您的return
语句
值得一提的是,在大多数代码中都有一个try-catch,它将异常包装到任务结果中,因此您可以在代码(或从代码调用的代码)中抛出,并在调度方法的异步部分时创建失败的任务,而不是未处理的异常 您可以将async
视为将结果(返回值和异常)包装到任务中
同样,wait
打开结果(提取返回值或引发异常)
我有一个更详细的计划,我建议跟进。另一方面,.很高兴将返回的guid自动包装到任务中。简短回答:编译器执行了一些黑魔法,将返回类型转换为任务。很长的一个答案涉及到理解编译器是如何生成状态机的,这些状态机必须使用wait
@chieftwoils来创建好的,这让我更加放心。但是,由于它会自动将内容包装到任务中,我如何/应该控制成功状态?在实际代码中,有一个场景,我希望任务失败,并且在API中的消费控制器中生成Ok(guid)
或NotFound(guid)
…@camiloterevento谢谢,伙计。目前我对这个简短的版本很满意。然而,由于这是自动行为,我想知道如何控制任务的成功状态。请看我上面的评论,了解实际的用例描述。这是好的部分,你不在乎。您知道,在调用var result=await-Awaited()之后代码>您将有一个Guid(或一个异常,如果是这样的话)
public async Task<Guid> Awaited()
{
Account account = new Account();
Context.Accounts.Add(account);
await Context.SaveChangesAsync();
return account.Id;
}
[AsyncStateMachine(typeof(<Awaited>d__0))]
public Task<Guid> Awaited()
{
<Awaited>d__0 stateMachine = default(<Awaited>d__0);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<Guid>.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder<Guid> <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[StructLayout(LayoutKind.Auto)]
[CompilerGenerated]
private struct <Awaited>d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<Guid> <>t__builder;
private Account <account>5__2;
private TaskAwaiter <>u__1;
private void MoveNext()
{
int num = <>1__state;
Guid id;
try
{
TaskAwaiter awaiter;
if (num != 0)
{
<account>5__2 = new Account();
Context.Accounts.Add(<account>5__2);
awaiter = Context.SaveChangesAsync().GetAwaiter();
if (!awaiter.IsCompleted)
{
num = (<>1__state = 0);
<>u__1 = awaiter;
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
return;
}
}
else
{
awaiter = <>u__1;
<>u__1 = default(TaskAwaiter);
num = (<>1__state = -1);
}
awaiter.GetResult();
id = <account>5__2.Id;
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult(id);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
<>t__builder.SetStateMachine(stateMachine);
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}