Refactoring Halfwit to use C# 5

With the announcement over the weekend that there would indeed be a Visual Studio 2012 Express SKU for Windows desktop development, I've been busy porting Halfwit to C# 5.

I'm not sure at this stage whether I'll turn this into "Halfwit 3" and have it run on .NET 4.5, or whether I'll use the Async Targeting Pack for Visual Studio 11 and leave it as a .NET 4 application. I'm leaning towards the former right now.

Anyway, here's an example of a ViewModel method and how it would change using the new syntax.

As you can see, I have a single method that will mark or unmark a tweet as a "favourite". Since I'm using Budgie as my Twitter client library, everything is represented as a Task and the code is already quite readable:

void ToggleFavourite()
{
    Task<ITwitterResponse<TwitterStatus>> task;
    if (IsFavourite)
    {
        task = Service.UnfavouriteAsync(Id);
    }
    else
    {
        task = Service.FavouriteAsync(Id);
    }

    task.ContinueOnUIThreadWith(t =>
        {
            if (t.IsFaulted)
            {
                _host.Status = t.ErrorMessage();
                return;
            }

            var response = t.Result;
            if (response.StatusCode != HttpStatusCode.OK)
            {
                _host.Status = response.ErrorMessage;
                return;
            }

            IsFavourite = !IsFavourite;
            if (IsFavourite)
            {
                _host.Status = "Status added to favourites";
            }
            else
            {
                _host.Status = "Status removed from favourites";
            }
        });
}

Here's the new version using C# 5's async and await keywords:

async void ToggleFavourite()
{
    try
    {
        ITwitterResponse<TwitterStatus> response;
        if (IsFavourite)
        {
            response = await Service.UnfavouriteAsync(Id);
        }
        else
        {
            response = await Service.FavouriteAsync(Id);
        }

        if (response.StatusCode != HttpStatusCode.OK)
        {
            _host.Status = response.ErrorMessage;
            return;
        }

        IsFavourite = !IsFavourite;
        if (IsFavourite)
        {
            _host.Status = "Status added to favourites";
        }
        else
        {
            _host.Status = "Status removed from favourites";
        }
    }
    catch (Exception ex)
    {
        _host.Status = ex.GetBaseException().Message;
    }
}

As you can see, this new version has a makes the error checking a bit more explicit, since I can simply wrap the whole thing in a try/catch block rather than checking the Task.IsFaulted property. It also makes the ContinueOnUIThreadWith(...) extension method unnecessary, as the await keyword knows to return on the calling thread.

One thing I did want to point out is the call to GetBaseException() in the catch block. This is a method that I only learned about on the weekend. It essentially looks for the innermost exception (by recursively checking the InnerException property) so you can get the root cause of an exception if there was a chain of them. Since Halfwit only does the bare-minimum of exception handling (catching it and reporting the message in the status bar) this was a really easy way to do that. This replaces all of the logic in my ErrorMessage() extension method on Task.

In my next post, I'll look at how I used the new new async keywords to replace the co-routine stuff from MadProps.MvvmLight.

c# halfwit .net budgie
Posted by: Matt Hamilton
Last revised: 20 Feb, 2017 08:20 PM History

Comments

No comments yet. Be the first!

No new comments are allowed on this post.