【问题标题】:Is this a good way to start a anonymous task and continue with ui thread?这是启动匿名任务并继续 ui 线程的好方法吗?
【发布时间】:2015-12-09 01:46:39
【问题描述】:

自从我使用任务和 lambda 表达式以来已经有一段时间了。这是用 lambda 表达式运行匿名任务然后在任务完成后在 UI 线程上运行代码的好方法吗?

private void btn_mods_Click(object sender, RoutedEventArgs e)
{
    function_buttons_stackpanel.IsEnabled = false;
    Loading();
    Task task = new Task(() => {
        if (IsServiceIsUp() != false)
        {
            webServiceMods = JsonConvert.DeserializeObject(_webServiceResponse).mods;
            webServiceBaseUrl = JsonConvert.DeserializeObject(_webServiceResponse).basePath;
            Console.Write(webServiceBaseUrl);

        }
    });
    task.Start();
    task.ContinueWith((foo) =>
    {
        FinishedLoading();
        function_buttons_stackpanel.IsEnabled = true;
    }, TaskScheduler.FromCurrentSynchronizationContext());

}

private void Loading()
{
    img_loading.Visibility = Visibility.Visible;
}

private void FinishedLoading()
{
    img_loading.Visibility = Visibility.Collapsed;
}

我试图链接任务。直接开始,但给了我一个错误Cannot Implicitly convert type void to System.Threading.Tasks.Task

基本上我想做的是将整个过程从头到尾链接起来。

Task task = new Task(() => {
    if (IsServiceIsUp() != false)
    {
        webServiceMods = JsonConvert.DeserializeObject(_webServiceResponse).mods;
        webServiceBaseUrl = JsonConvert.DeserializeObject(_webServiceResponse).basePath;
        Console.Write(webServiceBaseUrl);

    }
}).Start();

在 PHP 中我会这样做:

$task = new Task(() => {
    if (IsServiceIsUp() != false)
    {
        $webServiceMods = JsonConvert::DeserializeObject($_webServiceResponse).mods;
        $webServiceBaseUrl = JsonConvert::DeserializeObject($_webServiceResponse).basePath;
        Console::Write($webServiceBaseUrl);

    }
})
->Start()
->ContinueWith(($foo) =>
{
    FinishedLoading();
    $function_buttons_stackpanel.IsEnabled = true;
}, TaskScheduler::FromCurrentSynchronizationContext());

这可能吗?如果是这样,有什么理由不这样做,如果有更好的方法可以做到这一点,你能给我举个例子吗?

谢谢!

【问题讨论】:

  • 我会使用 async/await

标签: c# async-await task-parallel-library .net-4.5.2


【解决方案1】:

您可以使用async-await 更轻松地完成此操作:

private async void btn_mods_Click(object sender, RoutedEventArgs e)
{
    if (!IsServiceIsUp())
        return;

    function_buttons_stackpanel.IsEnabled = false;
    Loading();
    await Task.Run(() => 
    {
        var result = JsonConvert.DeserializeObject(_webServiceResponse);
        Console.Write(result.webServiceBaseUrl);
    });

    FinishedLoading();
    function_buttons_stackpanel.IsEnabled = true;
}

性能方面,我不太确定您是否需要使用线程池线程来反序列化 JSON。我肯定会测试这段代码以确定它是否值得。

【讨论】:

  • 谢谢!干净多了。
【解决方案2】:

如果您将事件处理程序声明为异步函数,那么您不必启动任务,它已经异步运行。

所有异步函数都应该返回 Task 而不是 void 和 Task<TResult> 而不是 TResult。唯一的例外是事件处理程序。事件处理程序返回 void

在适当的 async-await 中,如下所示:

private async void btn_mods_Click(object sender, RoutedEventArgs e)
{
    function_buttons_stackpanel.IsEnabled = false;
    Loading();
    if (IsServiceIsUp())
    {   // The service is up, start the deserialization
        // because this function is async, you can call other async functions
        // without having to start a task
        // The UI remains responsive
        webServiceMods = await JsonConvert.DeserializeObjectAsync(_webServiceResponse).mods;
        // because of the await above, the second task is started after the first is finished:
        webServiceBaseUrl = await JsonConvert.DeserializeObjectAsync(_webServiceResponse).basePath;
        // because of the await the second task is also finished            
        Console.Write(webServiceBaseUrl);
        FinishedLoading();
        function_buttons_stackpanel.IsEnabled = true;
    }
}

通过使您的事件处理程序异步,您的代码将充分利用 async-await。如果没有 async-await 时代之前的 continueWith 和其他 Task 相关函数的魔力,您的代码会看起来更整洁。

最后一句话:下面的代码看起来很傻而且不必要的困难:

if (IsServiceIsUp() != false) ...

这当然应该是:

if (IsServiceIsUp()) ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-02
    • 2014-08-03
    • 1970-01-01
    • 2012-03-26
    相关资源
    最近更新 更多