IAsyncStateMachine.SetStateMachine的目的是什么?

17

接口IAsyncStateMachine只能由编译器使用,在生成异步方法的状态机中使用。接口具有SetMachineState - 将状态机配置为堆分配的副本(来自msdn)。

我使用ILSpy反编译代码,发现了生成的状态机,并提到SetMachineState函数的实现始终为空,如下所示

[CompilerGenerated]
private sealed class <GetResult>d__1 : IAsyncStateMachine
{
    //some fields to hold state

    void IAsyncStateMachine.MoveNext()
    { ... }

    [DebuggerHidden]
    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
    {
        //Method is empty
    }
}

还有一件事,生成的状态机是一个类(class),而不是所有地方都声明的结构体(struct)。

那么问题来了: IAsyncStateMachine 接口的 SetStateMachine 函数的目的是什么?它在哪里被使用?

原始异步函数:

private static async Task<int> GetResult()
{
    var task = GetSomeData();
    DoSomeWork();
    return await task;
}

1
你用的异步代码是什么,来反编译这个?很可能你只是没有绑定。 - Random Dev
添加了原始的异步函数。 - Vasyl Senko
1
是的 - 我认为你不需要任何状态机 - 想一想:你可以直接返回 tasḱ,编译器可能会知道这个- 再添加至少一个异步函数/任务并重试。 - Random Dev
或者将await task放在DoSomeWork()前面,这样也会强制进行状态转换。 - Random Dev
1个回答

17

这是因为您正在查看一个debug版本而不是release版本。

将状态机设置为结构体是编译器的优化。当等待时,如果可等待对象已经完成,它可以避免分配内存。在调试时不需要此优化,否则会使在 Visual Studio 中实现调试功能更加困难。

如果您查看相同的代码在release中编译,则状态机确实将是一个结构体,并且SetStateMachine方法将不会为空,因为这个方法将状态机从栈移到堆中:

[CompilerGenerated]
[StructLayout(LayoutKind.Auto)]
private struct <GetResult>d__1 : IAsyncStateMachine
{
    public AsyncTaskMethodBuilder<int> <>t__builder;
    ...

    [DebuggerHidden]
    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
    {
        this.<>t__builder.SetStateMachine(stateMachine);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接