异步模式 - 在从方法返回某些值之前等待事件

Mob*_*erg 4 c# asynchronous async-await

[免责声明 - 此代码已简化(很多)以易于阅读,我知道它不符合正常的代码标准]

我的问题可以在下面的代码中看到。基本上我有一个解析对象的调用者。我必须等到子组件完成(由事件发出信号),然后才能从基于子组件上某个值的值返回值。

问题是:这种情况的首选模式是什么(当然,最欢迎实际的解决方案)。

我已经围绕 TaskCompletionSource 等尝试了不同的东西,但恐怕我的理解远远落后于找到(最好)优雅的解决方案。希望你能帮忙。

public class AsyncEventTest
{
    // This is performed one a single (UI) thread. The exception to this is
    // a.B that might - at the calling time - get a asycronious update from the backend.
    // The update is syncronized into the calling context so Task.Wait etc. will effectivly
    // deadlock the flow.
    public static string CallMe(A a)
    {
        if (a.B.State != State.Ready)
        {
            // wait for a.B.State == State.Ready ... but how ...
            // await MagicMethod() ???;
        }

        // only execute this code after a.b.State == State.Ready
        return a.B.Text;
    }
}

public class A
{
    public B B { get; set; }
}

public class B
{
    public State State { get; private set; }
    public event Action StateChanged;
    public string Text { get; }
}

public enum State { Ready, Working, }
Run Code Online (Sandbox Code Playgroud)

编辑 - 我尝试过的例子我想知道这样的方法是否是可以接受的方法(或者它是否有效)?

public class AsyncEventTest2
{
    public static string CallMe(A a)
    {
        return CallMe1(a).Result;
    }

    public async static Task<string> CallMe1(A a)
    {
        await CallMe2(a);
        return a.B.Text;
    }

    public static Task CallMe2(A a)
    {
        TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
        if (a.B.State != State.Ready)
        {
            a.B.StateChanged += () =>
                {
                    if (a.B.State == State.Ready)
                        tcs.SetResult(a.B.Text);
                };
        }
        else
        {
            tcs.SetResult(a.B.Text);
        }

        return tcs.Task;
    }
}
Run Code Online (Sandbox Code Playgroud)

Lee*_*Lee 6

您可以注册该StateChanged活动并使用TaskCompletionSource.

public static Task WaitForReady(this B b)
{
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    Action handler = null;
    handler = () =>
    {
        if (b.State == State.Ready)
        {
            b.StateChanged -= handler;
            tcs.SetResult(null);
        }
    };

    b.StateChanged += handler;
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果在注册处理程序之前可以引发事件,则可能会发生竞争。