Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步模式-在从方法返回某些值之前等待事件_C#_Asynchronous_Async Await - Fatal编程技术网

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

C# 异步模式-在从方法返回某些值之前等待事件,c#,asynchronous,async-await,C#,Asynchronous,Async Await,[免责声明-此代码简化(很多)以便于阅读,我知道它不符合正常的代码标准] 我的问题可以在下面的代码中看到。基本上我有一个在对象中解析的调用程序。我必须等到一个子组件完成(由一个事件发出信号),然后再返回一个基于该子组件上某个值的值 问题是:在这种情况下,首选的模式是什么(当然,最欢迎实际的解决方案) 我已经尝试过TaskCompletionSource等不同的东西,但恐怕我的理解还远远落后于找到一个(最好)优雅的解决方案。希望你能帮忙 public class AsyncEventTest {

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

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

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

我已经尝试过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, }
编辑-我尝试的示例 我想知道这样的方法是否可以接受(或者是否有效)

公共类AsyncEventTest2
{
公共静态字符串CallMe(A)
{
返回CallMe1(a).结果;
}
公共异步静态任务CallMe1(A)
{
等待电话2(a);
返回a.B.Text;
}
公共静态任务调用ME2(A)
{
TaskCompletionSource tcs=新的TaskCompletionSource();
如果(a.B.State!=状态就绪)
{
a、 B.StateChanged+=()=>
{
如果(a.B.State==State.Ready)
tcs.SetResult(a.B.Text);
};
}
其他的
{
tcs.SetResult(a.B.Text);
}
返回tcs.Task;
}
}

您可以注册
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;
}
公共静态任务WaitForReady(此B)
{
TaskCompletionSource tcs=新的TaskCompletionSource();
动作处理程序=null;
处理程序=()=>
{
if(b.State==State.Ready)
{
b、 StateChanged-=处理程序;
tcs.SetResult(空);
}
};
b、 StateChanged+=处理程序;
返回tcs.Task;
}

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

哪些类在您的控制之下?Ie你可以更改哪一个?然后用WaitHandle(
ManualResetEvent
)替换事件。好的,这需要很多重构,但我会用谷歌搜索它以找到它的使用方法(仍然希望有其他方法)。你在哪里将状态更改为就绪?这是异步更新(来自其他地方的上一个调用)从后端同步到UI线程。是的,这是我想到的,然后让调用方等待它。这是一个很好的观点,但幸运的是,我保证这是在单个线程上运行的。
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;
}