Udostępnij za pośrednictwem


A little something that made me happy…

Last week, I was doing some work on a utility I own. It talked to some servers in the background that could be slow at times and there was no way to know what was happening, so I needed to provide some way of telling the user that it was busy.

I started writing a unit test for it, and realized I needed an abstraction (R U busy? Yes, IBusy):

public interface IBusy
{
    void Start();
    void Stop();
}

I plumbed that into the code, failed the test, and then got it working, but it wasn’t very elegant. Plus, the way I have my code structured, I had to pass it into each of the managers that do async operations, and there are four of those.

The outlook was not very bright, but I can suffer when required, so I started implementing the next set.

Halfway through, I got an idea. When I added in the asynchronous stuff, I needed a way to abstract that out for testing purposes, so I had defined the following:

public interface ITaskCreator
{
    void StartTask<T>(Func<T> func, Action<T> action  );
}

This is very simple to use; pass in the function you want to happen asynchronously and the action to process your result. There is a TaskCreatorSynchronous class that I use in my unit tests; it looks like this:

public void StartTask<T>(Func<T> func, Action<T> action)
{
    action(func());
}

What I realized was that the times I needed to show the code was busy were exactly the times when I was running a task, and I already had a class that knew how to do that.  I modified TaskCreator:

public class TaskCreator : ITaskCreator
{
    public EventHandlerEmpty StartedTask;
    public EventHandlerEmpty FinishedTask;

    public void StartTask<T>(Func<T> func,
        Action<T> action  )
    {
        if (StartedTask != null)
        {
            StartedTask();
        }

        Task<T>.Factory.StartNew(func)
            .ContinueWith((task) =>
            {
                action(task.Result);
                if (FinishedTask != null)
                {
                    FinishedTask();
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());
    }
}

It now has an event that is called before the task is started and one that is called after the task is completed. All my main code has to do is hook up appropriately to those events, and any class that uses that instance to create tasks will automatically get the busy functionality.

I am happy when things turn out so neatly.