【问题标题】:Instructing method to return only after anonymous event handler finishes仅在匿名事件处理程序完成后指示方法返回
【发布时间】:2015-10-16 18:45:48
【问题描述】:

在我使用 WebBrowser 的静态方法中。我订阅了它的导航事件一个匿名方法。我可以指示我的方法仅在 WebBroswer 触发导航事件并且我的匿名处理程序完成后返回吗?

using forms = System.Windows.Forms;
namespace ProxyProvider
{
    public delegate string finished();
    public static class ProxyProvider
    {
        public static string GetProxy()
        {
            string returnValue = "";
            finished meFinished = () =>
            {
                return returnValue;
            };
            forms.WebBrowser browser = new forms.WebBrowser();
            try
            {
                browser.Navigated += (s, e) =>
                {
                    if (browser.ReadyState == forms.WebBrowserReadyState.Loading) //waiting for browser finishes loading page
                        return;
                    returnValue = ParseHtml(browser.DocumentText); 
                    meFinished();  //I want this function to return only here. After it finishes parsing
                };
                browser.Navigate("http://example.com/proxy-list/");
                return returnValue;  // don't want to return it here
            }
            catch (Exception e)
            {
                forms.MessageBox.Show("ProxyProvider.GetProxy(): " + e.Message);
                return "";
            }
        }
}
}

【问题讨论】:

    标签: c#


    【解决方案1】:

    你可以,但你必须调整一些东西。

    这里的基本概念是您的主要方法将阻塞,直到从事件处理程序中设置一个值。由于您目前处于 UI 线程上,因此您希望异步完成此操作(以便您的窗口保持响应)。

    首先我们需要更改方法的签名:

    public static Task<string> GetProxy()
    

    我们将在此处返回一个 Task 对象,以便调用者可以等待我们并获取字符串返回值。然后你需要设置一个TaskCompletionSource并在handler中设置:

    TaskCompletionSource<string> navTaskSource= new TaksCompletionSource<string>();
    browser.Navigated += (s, e) =>
    {
         if (browser.ReadyState == forms.WebBrowserReadyState.Loading)
              return;
         string returnValue = ParseHtml(browser.DocumentText); 
         navTaskSource.TrySetResult(returnValue);
    };
    

    现在你已经完成了,只需返回任务:

    browser.Navigate("http://example.com/proxy-list/");
    return navTaskSource.Task;
    

    你的调用代码应该awaitthis方法避免任何UI线程阻塞并获取返回值。

    string proxy = await MyClass.GetProxy();
    

    请注意,包含await 的方法必须标记为async

    【讨论】:

    • 不需要创建async的方法。直接返回tcs的Task即可。此外,将 TCS 命名为navTask 具有误导性。它不是任务,它是任务的完成源,应该相应地命名。此外,他的方法不是有一个TaskCompletionSource&lt;bool&gt;,而是产生一个string,所以它应该是一个TaskCompletionSource&lt;string&gt;,其中设置了字符串结果并将其传递给调用者。最后,此处理程序在调用一次后取消订阅可能很重要。
    • 哦,在您的代码中,假设您在调用Navigate(启动任务正在等待的操作)之前正在等待任务,代码将死锁。导航必须是第一位的。
    • @Servy 所有优点。我已经编辑修复(死锁非常好,甚至没有注意到。
    猜你喜欢
    • 2018-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多