├── ConsoleApplicationBase ├── App.config ├── ConsoleFormatting.cs ├── Commands │ ├── Users.cs │ └── DefaultCommands.cs ├── Properties │ └── AssemblyInfo.cs ├── Models │ └── SampleData.cs ├── ConsoleCommand.cs ├── ConsoleApplicationBase.csproj └── Program.cs ├── .gitignore ├── ConsoleApplicationBase.sln └── README.md /ConsoleApplicationBase/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | *.obj 3 | *.exe 4 | *.pdb 5 | *.user 6 | *.aps 7 | *.pch 8 | *.vspscc 9 | *_i.c 10 | *_p.c 11 | *.ncb 12 | *.suo 13 | *.sln.docstates 14 | *.tlb 15 | *.tlh 16 | *.bak 17 | *.cache 18 | *.ilk 19 | *.log 20 | [Bb]in 21 | [Dd]ebug*/ 22 | *.lib 23 | *.sbr 24 | obj/ 25 | [Rr]elease*/ 26 | _ReSharper*/ 27 | [Tt]est[Rr]esult* 28 | *.vssscc 29 | $tf*/ -------------------------------------------------------------------------------- /ConsoleApplicationBase/ConsoleFormatting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | // code was found at the C# Examples Site: http://www.csharp-examples.net/indent-string-with-spaces/ 8 | 9 | namespace ConsoleApplicationBase 10 | { 11 | public class ConsoleFormatting 12 | { 13 | public static string Indent(int count) 14 | { 15 | return "".PadLeft(count); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ConsoleApplicationBase.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30723.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApplicationBase", "ConsoleApplicationBase\ConsoleApplicationBase.csproj", "{D21CC334-9E7D-4A29-B6F9-5120351EC703}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {D21CC334-9E7D-4A29-B6F9-5120351EC703}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {D21CC334-9E7D-4A29-B6F9-5120351EC703}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {D21CC334-9E7D-4A29-B6F9-5120351EC703}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {D21CC334-9E7D-4A29-B6F9-5120351EC703}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /ConsoleApplicationBase/Commands/Users.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ConsoleApplicationBase.Models; 7 | 8 | namespace ConsoleApplicationBase.Commands 9 | { 10 | public static class Users 11 | { 12 | public static string Create(string firstName, string lastName) 13 | { 14 | Nullable maxId = (from u in SampleData.Users 15 | select u.Id).Max(); 16 | int newId = 0; 17 | if(maxId.HasValue) 18 | { 19 | newId = maxId.Value + 1; 20 | } 21 | 22 | var newUser = new User { Id = newId, FirstName = firstName, LastName = lastName }; 23 | SampleData.Users.Add(newUser); 24 | return ""; 25 | } 26 | 27 | 28 | public static string Get() 29 | { 30 | var sb = new StringBuilder(); 31 | foreach(var user in SampleData.Users) 32 | { 33 | sb.AppendLine(ConsoleFormatting.Indent(2) + string.Format("Id:{0} {1} {2}", user.Id, user.FirstName, user.LastName)); 34 | } 35 | return sb.ToString(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ConsoleApplicationBase/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ConsoleApplicationBase")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ConsoleApplicationBase")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b776aaea-d3a1-435e-b7cf-623792acc812")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ConsoleApplicationBase/Models/SampleData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ConsoleApplicationBase.Models 8 | { 9 | // We'll use this for our examples: 10 | public class User 11 | { 12 | public int Id { get; set; } 13 | public string FirstName { get; set; } 14 | public string LastName { get; set; } 15 | } 16 | 17 | 18 | public static class SampleData 19 | { 20 | private static List _userData; 21 | public static List Users 22 | { 23 | get 24 | { 25 | // List will be initialized with data the first time the 26 | // static property is accessed: 27 | if(_userData == null) 28 | { 29 | _userData = CreateInitialUsers(); 30 | } 31 | return _userData; 32 | } 33 | } 34 | 35 | 36 | // Some test data: 37 | static List CreateInitialUsers() 38 | { 39 | var initialUsers = new List() 40 | { 41 | new User { Id = 1, FirstName = "John", LastName = "Lennon" }, 42 | new User { Id = 2, FirstName = "Paul", LastName = "McCartney" }, 43 | new User { Id = 3, FirstName = "George", LastName = "Harrison" }, 44 | new User { Id = 4, FirstName = "Ringo", LastName = "Starr" }, 45 | }; 46 | return initialUsers; 47 | 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ConsoleApplicationBase/Commands/DefaultCommands.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | // All console commands must be in the sub-namespace Commands: 8 | namespace ConsoleApplicationBase.Commands 9 | { 10 | // Must be a public static class: 11 | public static class DefaultCommands 12 | { 13 | // Methods used as console commands must be public and must return a string 14 | 15 | public static string DoSomething(int id, string data) 16 | { 17 | return string.Format(ConsoleFormatting.Indent(2) + 18 | "I did something to the record Id {0} and saved the data '{1}'", id, data); 19 | } 20 | 21 | 22 | public static string DoSomethingElse(DateTime date) 23 | { 24 | return string.Format(ConsoleFormatting.Indent(2) + "I did something else on {0}", date); 25 | } 26 | 27 | 28 | public static string DoSomethingOptional(int id, string data = "No Data Provided") 29 | { 30 | var result = string.Format(ConsoleFormatting.Indent(2) + 31 | "I did something to the record Id {0} and saved the data {1}", id, data); 32 | 33 | if(data == "No Data Provided") 34 | { 35 | result = string.Format(ConsoleFormatting.Indent(2) + 36 | "I did something to the record Id {0} but the optinal parameter " 37 | + "was not provided, so I saved the value '{1}'", id, data); 38 | } 39 | return result; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ConsoleApplicationBase/ConsoleCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Text.RegularExpressions; 7 | using ConsoleApplicationBase.Commands; 8 | 9 | namespace ConsoleApplicationBase 10 | { 11 | public class ConsoleCommand 12 | { 13 | public ConsoleCommand(string input) 14 | { 15 | // Ugly regex to split string on spaces, but preserve quoted text intact: 16 | var stringArray = 17 | Regex.Split(input, "(?<=^[^\"]*(?:\"[^\"]*\"[^\"]*)*) (?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"); 18 | 19 | _arguments = new List(); 20 | for (int i = 0; i < stringArray.Length; i++) 21 | { 22 | // The first element is always the command: 23 | if (i == 0) 24 | { 25 | this.Name = stringArray[i]; 26 | 27 | // Set the default: 28 | this.LibraryClassName = "DefaultCommands"; 29 | string[] s = stringArray[0].Split('.'); 30 | if (s.Length == 2) 31 | { 32 | this.LibraryClassName = s[0]; 33 | this.Name = s[1]; 34 | } 35 | } 36 | else 37 | { 38 | var inputArgument = stringArray[i]; 39 | 40 | // Assume that most of the time, the input argument is NOT quoted text: 41 | string argument = inputArgument; 42 | 43 | // Is the argument a quoted text string? 44 | var regex = new Regex("\"(.*?)\"", RegexOptions.Singleline); 45 | var match = regex.Match(inputArgument); 46 | 47 | // If it IS quoted, there will be at least one capture: 48 | if (match.Captures.Count > 0) 49 | { 50 | // Get the unquoted text from within the qoutes: 51 | var captureQuotedText = new Regex("[^\"]*[^\"]"); 52 | var quoted = captureQuotedText.Match(match.Captures[0].Value); 53 | 54 | // The argument should include all text from between the quotes 55 | // as a single string: 56 | argument = quoted.Captures[0].Value; 57 | } 58 | _arguments.Add(argument); 59 | } 60 | } 61 | } 62 | 63 | public string Name { get; set; } 64 | public string LibraryClassName { get; set; } 65 | 66 | private List _arguments; 67 | public IEnumerable Arguments 68 | { 69 | get 70 | { 71 | return _arguments; 72 | } 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /ConsoleApplicationBase/ConsoleApplicationBase.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D21CC334-9E7D-4A29-B6F9-5120351EC703} 8 | Exe 9 | Properties 10 | ConsoleApplicationBase 11 | ConsoleApplicationBase 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A Useful, Interactive, and Extensible .NET Console Application Template for Development and Testing 2 | =================================================================================================== 3 | 4 | This application can serve as a template of framework into which you can easily plug in commands related tothe code you want to demo, excercise, or which forms the business layer of an actual Console application. The "Interactive" part of this Console is already in place - all you need to do is plug command classes and methods into the Commands namespace and you're ready to go. 5 | 6 | The goal here was not to emulate a fully-functioning Shell or terminal. I wanted to be able to: 7 | 8 | * Run the program, be greeted with a prompt (customizable, in this case), and then enter commands corresponding to various methods defined in a specific area of the application. 9 | * Receive feedback (where appropriate), error messages, and such 10 | * Easily add/remove commands 11 | * Generally be able to quickly put together a functioning console application, with predictable and familiar interactive behavior, without re-inventing the wheel every time. 12 | 13 | For more detailed information about how this works, see the Blog post at: [C#: Building a Useful, Extensible .NET Console Application Template for Development and Testing](http://typecastexception.com/post/2014/09/07/C-Building-a-Useful-Extensible-NET-Console-Application-Template-for-Development-and-Testing.aspx) 14 | 15 | Assumptions 16 | ----------- 17 | 18 | As it is currently configured, this application makes a few assumptions about architecture. You can easily adapt things to suit your purposes, but out-of-the-box, the following "rules" are assumed: 19 | 20 | * Methods representing Console commands will be defined as `public static` methods which always return a `string`, and are defined on `public static` classes. 21 | * Classes containing methods representing Console commands will be located in the `Commands` namespace, and in the *Commands* folder. 22 | * There will always be a static class named `DefaultCommands` from which methods may be invoked from the Console directly by name. For many console projects, this will likely be sufficient. 23 | * Commands defined on classes other than DefaultCommands will be invoked from the console using the familiar dot syntax: ClassName.CommandName. 24 | 25 | Defining Commands 26 | ----------------- 27 | 28 | If you were to define the following (trival example-style) commands in your `DefaultCommands` class, you will be able to execute these from the Console when you run the application. The DefaultCommands class must be present in the project, and must be within the `Commands` namespace (note that the methods must be `static` in order to be available to the console as commands, and the project assumes a `string` return type), 29 | 30 | ```csharp 31 | public static string DoSomething(int id, string data) 32 | { 33 | return string.Format(ConsoleFormatting.Indent(2) + 34 | "I did something to the record Id {0} and saved the data '{1}'", id, data); 35 | } 36 | 37 | 38 | public static string DoSomethingElse(DateTime date) 39 | { 40 | return string.Format(ConsoleFormatting.Indent(2) + "I did something else on {0}", date); 41 | } 42 | 43 | 44 | public static string DoSomethingOptional(int id, string data = "No Data Provided") 45 | { 46 | var result = string.Format(ConsoleFormatting.Indent(2) + 47 | "I did something to the record Id {0} and saved the data {1}", id, data); 48 | 49 | if(data == "No Data Provided") 50 | { 51 | result = string.Format(ConsoleFormatting.Indent(2) + 52 | "I did something to the record Id {0} but the optinal parameter " 53 | + "was not provided, so I saved the value '{1}'", id, data); 54 | } 55 | return result; 56 | } 57 | ``` 58 | 59 | Executing Commands 60 | ------------------ 61 | 62 | The commands above can be executed when you run the application with the following syntax: 63 | 64 | Execute the `DoSomething` command: 65 | 66 | ``` 67 | console> DoSomething 55 "My Data" 68 | ``` 69 | 70 | Execute the `DoSomethingElse` command: 71 | 72 | ``` 73 | console> DoSomethingElse 7/4/2014 74 | ``` 75 | The console recognizes and deals with optional method parameters. 76 | 77 | Execute the `DoSomethingOptional` command inluding optional parameters: 78 | 79 | ``` 80 | console> DoSomethingOptional 212 "This is my optional data" 81 | ``` 82 | 83 | OR, you could omit the last argument, and the default value defined on the method will be used: 84 | 85 | ``` 86 | console> DoSomethingOptional 212 87 | ``` 88 | 89 | I'm happy to take pull requests, suggestions, and ideas. 90 | -------------------------------------------------------------------------------- /ConsoleApplicationBase/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Reflection; 7 | 8 | namespace ConsoleApplicationBase 9 | { 10 | class Program 11 | { 12 | const string _commandNamespace = "ConsoleApplicationBase.Commands"; 13 | static Dictionary>> _commandLibraries; 14 | 15 | static void Main(string[] args) 16 | { 17 | Console.Title = typeof(Program).Name; 18 | 19 | // Any static classes containing commands for use from the 20 | // console are located in the Commands namespace. Load 21 | // references to each type in that namespace via reflection: 22 | _commandLibraries = new Dictionary>>(); 24 | 25 | // Use reflection to load all of the classes in the Commands namespace: 26 | var q = from t in Assembly.GetExecutingAssembly().GetTypes() 27 | where t.IsClass && t.Namespace == _commandNamespace 28 | select t; 29 | var commandClasses = q.ToList(); 30 | 31 | foreach (var commandClass in commandClasses) 32 | { 33 | // Load the method info from each class into a dictionary: 34 | var methods = commandClass.GetMethods(BindingFlags.Static | BindingFlags.Public); 35 | var methodDictionary = new Dictionary>(); 36 | foreach (var method in methods) 37 | { 38 | string commandName = method.Name; 39 | methodDictionary.Add(commandName, method.GetParameters()); 40 | } 41 | // Add the dictionary of methods for the current class into a dictionary of command classes: 42 | _commandLibraries.Add(commandClass.Name, methodDictionary); 43 | } 44 | Run(); 45 | } 46 | 47 | 48 | static void Run() 49 | { 50 | while (true) 51 | { 52 | var consoleInput = ReadFromConsole(); 53 | if (string.IsNullOrWhiteSpace(consoleInput)) continue; 54 | 55 | try 56 | { 57 | // Create a ConsoleCommand instance: 58 | var cmd = new ConsoleCommand(consoleInput); 59 | 60 | // Execute the command: 61 | string result = Execute(cmd); 62 | 63 | // Write out the result: 64 | WriteToConsole(result); 65 | } 66 | catch (Exception ex) 67 | { 68 | // OOPS! Something went wrong - Write out the problem: 69 | WriteToConsole(ex.Message); 70 | } 71 | } 72 | } 73 | 74 | 75 | static string Execute(ConsoleCommand command) 76 | { 77 | // Validate the class name and command name: 78 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 79 | 80 | string badCommandMessage = string.Format("" 81 | + "Unrecognized command \'{0}.{1}\'. " 82 | + "Please type a valid command.", 83 | command.LibraryClassName, command.Name); 84 | 85 | // Validate the command name: 86 | if (!_commandLibraries.ContainsKey(command.LibraryClassName)) 87 | { 88 | return badCommandMessage; 89 | } 90 | var methodDictionary = _commandLibraries[command.LibraryClassName]; 91 | if (!methodDictionary.ContainsKey(command.Name)) 92 | { 93 | return badCommandMessage; 94 | } 95 | 96 | // Make sure the corret number of required arguments are provided: 97 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 98 | 99 | var methodParameterValueList = new List(); 100 | IEnumerable paramInfoList = methodDictionary[command.Name].ToList(); 101 | 102 | // Validate proper # of required arguments provided. Some may be optional: 103 | var requiredParams = paramInfoList.Where(p => p.IsOptional == false); 104 | var optionalParams = paramInfoList.Where(p => p.IsOptional == true); 105 | int requiredCount = requiredParams.Count(); 106 | int optionalCount = optionalParams.Count(); 107 | int providedCount = command.Arguments.Count(); 108 | 109 | if (requiredCount > providedCount) 110 | { 111 | return string.Format( 112 | "Missing required argument. {0} required, {1} optional, {2} provided", 113 | requiredCount, optionalCount, providedCount); 114 | } 115 | 116 | // Make sure all arguments are coerced to the proper type, and that there is a 117 | // value for every emthod parameter. The InvokeMember method fails if the number 118 | // of arguments provided does not match the number of parameters in the 119 | // method signature, even if some are optional: 120 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 121 | 122 | if (paramInfoList.Count() > 0) 123 | { 124 | // Populate the list with default values: 125 | foreach (var param in paramInfoList) 126 | { 127 | // This will either add a null object reference if the param is required 128 | // by the method, or will set a default value for optional parameters. in 129 | // any case, there will be a value or null for each method argument 130 | // in the method signature: 131 | methodParameterValueList.Add(param.DefaultValue); 132 | } 133 | 134 | // Now walk through all the arguments passed from the console and assign 135 | // accordingly. Any optional arguments not provided have already been set to 136 | // the default specified by the method signature: 137 | for (int i = 0; i < command.Arguments.Count(); i++) 138 | { 139 | var methodParam = paramInfoList.ElementAt(i); 140 | var typeRequired = methodParam.ParameterType; 141 | object value = null; 142 | try 143 | { 144 | // Coming from the Console, all of our arguments are passed in as 145 | // strings. Coerce to the type to match the method paramter: 146 | value = CoerceArgument(typeRequired, command.Arguments.ElementAt(i)); 147 | methodParameterValueList.RemoveAt(i); 148 | methodParameterValueList.Insert(i, value); 149 | } 150 | catch (ArgumentException ex) 151 | { 152 | string argumentName = methodParam.Name; 153 | string argumentTypeName = typeRequired.Name; 154 | string message = 155 | string.Format("" 156 | + "The value passed for argument '{0}' cannot be parsed to type '{1}'", 157 | argumentName, argumentTypeName); 158 | throw new ArgumentException(message); 159 | } 160 | } 161 | } 162 | 163 | // Set up to invoke the method using reflection: 164 | // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 165 | 166 | Assembly current = typeof(Program).Assembly; 167 | 168 | // Need the full Namespace for this: 169 | Type commandLibaryClass = 170 | current.GetType(_commandNamespace + "." + command.LibraryClassName); 171 | 172 | object[] inputArgs = null; 173 | if (methodParameterValueList.Count > 0) 174 | { 175 | inputArgs = methodParameterValueList.ToArray(); 176 | } 177 | var typeInfo = commandLibaryClass; 178 | 179 | // This will throw if the number of arguments provided does not match the number 180 | // required by the method signature, even if some are optional: 181 | try 182 | { 183 | var result = typeInfo.InvokeMember( 184 | command.Name, 185 | BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, 186 | null, null, inputArgs); 187 | return result.ToString(); 188 | } 189 | catch (TargetInvocationException ex) 190 | { 191 | throw ex.InnerException; 192 | } 193 | } 194 | 195 | 196 | static object CoerceArgument(Type requiredType, string inputValue) 197 | { 198 | var requiredTypeCode = Type.GetTypeCode(requiredType); 199 | string exceptionMessage = 200 | string.Format("Cannnot coerce the input argument {0} to required type {1}", 201 | inputValue, requiredType.Name); 202 | 203 | object result = null; 204 | switch (requiredTypeCode) 205 | { 206 | case TypeCode.String: 207 | result = inputValue; 208 | break; 209 | 210 | case TypeCode.Int16: 211 | short number16; 212 | if (Int16.TryParse(inputValue, out number16)) 213 | { 214 | result = number16; 215 | } 216 | else 217 | { 218 | throw new ArgumentException(exceptionMessage); 219 | } 220 | break; 221 | 222 | case TypeCode.Int32: 223 | int number32; 224 | if (Int32.TryParse(inputValue, out number32)) 225 | { 226 | result = number32; 227 | } 228 | else 229 | { 230 | throw new ArgumentException(exceptionMessage); 231 | } 232 | break; 233 | 234 | case TypeCode.Int64: 235 | long number64; 236 | if (Int64.TryParse(inputValue, out number64)) 237 | { 238 | result = number64; 239 | } 240 | else 241 | { 242 | throw new ArgumentException(exceptionMessage); 243 | } 244 | break; 245 | 246 | case TypeCode.Boolean: 247 | bool trueFalse; 248 | if (bool.TryParse(inputValue, out trueFalse)) 249 | { 250 | result = trueFalse; 251 | } 252 | else 253 | { 254 | throw new ArgumentException(exceptionMessage); 255 | } 256 | break; 257 | 258 | case TypeCode.Byte: 259 | byte byteValue; 260 | if (byte.TryParse(inputValue, out byteValue)) 261 | { 262 | result = byteValue; 263 | } 264 | else 265 | { 266 | throw new ArgumentException(exceptionMessage); 267 | } 268 | break; 269 | 270 | case TypeCode.Char: 271 | char charValue; 272 | if (char.TryParse(inputValue, out charValue)) 273 | { 274 | result = charValue; 275 | } 276 | else 277 | { 278 | throw new ArgumentException(exceptionMessage); 279 | } 280 | break; 281 | 282 | case TypeCode.DateTime: 283 | DateTime dateValue; 284 | if (DateTime.TryParse(inputValue, out dateValue)) 285 | { 286 | result = dateValue; 287 | } 288 | else 289 | { 290 | throw new ArgumentException(exceptionMessage); 291 | } 292 | break; 293 | case TypeCode.Decimal: 294 | Decimal decimalValue; 295 | if (Decimal.TryParse(inputValue, out decimalValue)) 296 | { 297 | result = decimalValue; 298 | } 299 | else 300 | { 301 | throw new ArgumentException(exceptionMessage); 302 | } 303 | break; 304 | case TypeCode.Double: 305 | Double doubleValue; 306 | if (Double.TryParse(inputValue, out doubleValue)) 307 | { 308 | result = doubleValue; 309 | } 310 | else 311 | { 312 | throw new ArgumentException(exceptionMessage); 313 | } 314 | break; 315 | case TypeCode.Single: 316 | Single singleValue; 317 | if (Single.TryParse(inputValue, out singleValue)) 318 | { 319 | result = singleValue; 320 | } 321 | else 322 | { 323 | throw new ArgumentException(exceptionMessage); 324 | } 325 | break; 326 | case TypeCode.UInt16: 327 | UInt16 uInt16Value; 328 | if (UInt16.TryParse(inputValue, out uInt16Value)) 329 | { 330 | result = uInt16Value; 331 | } 332 | else 333 | { 334 | throw new ArgumentException(exceptionMessage); 335 | } 336 | break; 337 | case TypeCode.UInt32: 338 | UInt32 uInt32Value; 339 | if (UInt32.TryParse(inputValue, out uInt32Value)) 340 | { 341 | result = uInt32Value; 342 | } 343 | else 344 | { 345 | throw new ArgumentException(exceptionMessage); 346 | } 347 | break; 348 | case TypeCode.UInt64: 349 | UInt64 uInt64Value; 350 | if (UInt64.TryParse(inputValue, out uInt64Value)) 351 | { 352 | result = uInt64Value; 353 | } 354 | else 355 | { 356 | throw new ArgumentException(exceptionMessage); 357 | } 358 | break; 359 | default: 360 | throw new ArgumentException(exceptionMessage); 361 | } 362 | return result; 363 | } 364 | 365 | 366 | public static void WriteToConsole(string message = "") 367 | { 368 | if(message.Length > 0) 369 | { 370 | Console.WriteLine(message); 371 | } 372 | } 373 | 374 | 375 | const string _readPrompt = "console> "; 376 | public static string ReadFromConsole(string promptMessage = "") 377 | { 378 | // Show a prompt, and get input: 379 | Console.Write(_readPrompt + promptMessage); 380 | return Console.ReadLine(); 381 | } 382 | } 383 | } 384 | --------------------------------------------------------------------------------