patterncsharpModerate
Design patterns for console commands
Viewed 0 times
commandsdesignpatternsforconsole
Problem
I've made a pretty standard console in which you type a command and it does something. However, the issue that comes to my mind is scaling: if I want to add hundreds of commands, I have to manually add a new
The full code is stored in this GitHub repository.
Program.cs
CommandRegistry.cs
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace
Command instance for each one individually, which is... less than ideal.The full code is stored in this GitHub repository.
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConsolePlus.Commands;
namespace ConsolePlus
{
public class Program
{
///
/// The version of the program.
///
public const string Version = "1.0.0.0";
public static CommandRegistry Registry = new CommandRegistry();
///
/// The application's entry point.
///
/// The command-line arguments passed to the program.
public static void Main(string[] args)
{
CommandHandler.RegisterCommands();
Console.WriteLine("ConsolePlus v." + Version);
while (true)
{
Console.Write(">>> ");
string line = Console.ReadLine();
List parts = line.Split(' ').ToList();
string commandName = parts[0];
parts.RemoveAt(0);
string[] commandArgs = parts.ToArray();
try
{
string result = Registry.Execute(commandName, commandArgs);
if (result != null)
{
Console.WriteLine("[{0}] {1}", commandName, result);
}
}
catch (CommandNotFoundException)
{
Console.WriteLine("[ConsolePlus] No such command.");
}
}
}
}
}CommandRegistry.cs
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace
Solution
Why do you have the
You can then query your assembly file for classes where
Also, does
I would also recommend to remove the setters from the properties in
Command class? Why not make life much simpler for yourself by making AllCommands a List, and having classes like ClearCommand implement ICommand? You can then query your assembly file for classes where
ICommand is implemented; that way you don't even need to fill AllCommands "by hand":AllCommands = Assembly.GetExecutingAssembly().GetTypes()
.Where(x => x.GetInterfaces().Contains(typeof(ICommand))
&& x.GetConstructor(Type.EmptyTypes) != null)
.Select(x => Activator.CreateInstance(x) as ICommand);Also, does
AllCommands need to be called AllCommands? Can't it just be called Commands?I would also recommend to remove the setters from the properties in
ICommand. That way you'd end up with something like this:public interface ICommand
{
string Name { get; }
string HelpText { get; }
bool IsPrivileged { get; }
string Execute(string[] args);
}
public class ClearCommand : ICommand
{
public string Name { get { return "clear"; } }
public string HelpText { get { return "Clears the console screen."; } }
public bool IsPrivileged { get { return false; } }
public string Execute(string[] args)
{
Console.Clear();
return null;
}
}Code Snippets
AllCommands = Assembly.GetExecutingAssembly().GetTypes()
.Where(x => x.GetInterfaces().Contains(typeof(ICommand))
&& x.GetConstructor(Type.EmptyTypes) != null)
.Select(x => Activator.CreateInstance(x) as ICommand);public interface ICommand
{
string Name { get; }
string HelpText { get; }
bool IsPrivileged { get; }
string Execute(string[] args);
}
public class ClearCommand : ICommand
{
public string Name { get { return "clear"; } }
public string HelpText { get { return "Clears the console screen."; } }
public bool IsPrivileged { get { return false; } }
public string Execute(string[] args)
{
Console.Clear();
return null;
}
}Context
StackExchange Code Review Q#105675, answer score: 17
Revisions (0)
No revisions yet.