1

Let's say I'm building a simple console app which has three commands:

  1. Create category.
  2. Download recipe from API to category.
  3. Display all recipes in a category.

Assuming the app will grow, I use the Command design pattern to handle console commands. I also use a factory design pattern to create the commands from the user input. Correct me if this is not a good approach so far.

1 and 3 are synchronous commands. 2 is asynchronous. I should be able to initiate multiple downloads before they finish.

So in these models, if I create a Command interface to handle these requests and write something back to the console, how do I do this without violating this "rule"?

The goal would be to have a simple loop that parses the lines, transforms them into Commands and executes them. These methods don't know what they are executing as the logic is hidden in the concrete Commands.

Something alone these lines:

For (...)
{
    ...
    ICommand command = CommandFactory.From(string)

    Task t = command.executeAsync()
    tasks.Add(t)
}

Task.Waitall(tasks)

This works but it feels weird to have a executeAsync even when the command is sync. Although it works by doing Task.CompletedTask

New contributor
Myntekt is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • 1
    Why are 1 and 3 not asynchronous in a “this may yield control back to the CPU” way? – Telastyn Oct 16 at 23:42
  • 1
    "Let's say I'm building a simple console app which has four commands:" -- What's the fourth command? – Erik Eidt Oct 17 at 0:07
  • I meant 3, sorry. How would I do that @Telastyn? The point is that synchronous commands have to be fully executed before another command begins. – Myntekt Oct 17 at 0:20
  • @Myntekt - that isn’t what the async keyword does in C#. – Telastyn Oct 17 at 0:43
  • An async method will somewhere inside the method 'wait' for something. While it's waiting it gives control to the CPU. A synchronous method never waits for anything so it shouldn't be async. I don't know if there's something I'm missing. – Myntekt Oct 17 at 0:49
0

I would probably rename executeAsync into execute, and make it return null when the command is a synchronous one. This will allow it to implement the command interpreter along the lines of this:

var tasks = new List<Task>();
while(!commandQueue.IsEmpty())
{
    ICommand command = commandQueue.Next(); // inside: CommandFactory.From(string)
    Task t = command.execute();
    if(t==null)
    {
       Task.WaitAll(tasks.ToArray());
       tasks.Clear();
    }
    else
    {
       tasks.Add(t)
    }
}
Task.Waitall(tasks.ToArray());
tasks.Clear();

This way, asynchronous commands which are follow each other sequentially are executed in parallel until a synchronous command occurs.

If using null is not explicit enough for someones taste, one could alternatively add something like an IsAsync method to the ICommand interface, or use Task.CompletedTask as the return value for a synchronous command, but I prefer to keep things as simple as possible.

| improve this answer | |

Your Answer

Myntekt is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.