So I wrote this for my Mandelbrot Generator, to collect and use input from the user, and I made it dynamic enough to be useful anywhere.
I'm really interested in all critiques of it, as I'm going to be using it a lot now.
The idea is to allow the user to easily show messages on the console, that require input. Once valid input is received, the method returns.
Example usage:
int numberOfCores = Environment.ProcessorCount - 1; numberOfCores = Prompt($"Enter the number of cores to use (1 to {Environment.ProcessorCount})", false, numberOfCores, $"The value must be between 1 and {Environment.ProcessorCount}", delegate (int x) { return x >= 1 && x <= Environment.ProcessorCount; }); This will prompt the user to enter a value between 1 and Environment.ProcessorCount. But, you could also use:
ushort maxIterations = 1000; maxIterations = Prompt("Enter the maximum number of iterations", false, maxIterations); Which will only prompt the user for a valid ushort value.
/// <summary> /// This will repeatedly prompt the user with a message and request input, then return said input (if valid). /// </summary> /// <typeparam name="T">The type of input that should be returned.</typeparam> /// <param name="message">The message to initally display to the user.</param> /// <param name="requireValue">Whether or not to allow use of a `defaultValue`.</param> /// <param name="defaultValue">The default value to be returned if a user enters an empty line (`""`).</param> /// <param name="failureMessage">The message to display on a failure. If null, then the `message` parameter will be displayed on failure.</param> /// <param name="validationMethod">An optional delegate to a method which can perform additional validation if the input is of the target type.</param> /// <returns>The input collected from the user when it is deemed valid.</returns> static T Prompt<T>(string message, bool requireValue, T defaultValue = default(T), string failureMessage = null, Func<T, bool> validationMethod = null) where T : struct { if (!requireValue) Console.Write(string.Format(message + " [{0}]: ", defaultValue)); else Console.Write(message + ": "); bool pass = false; T result = default(T); while (!pass) { string line = Console.ReadLine(); if (requireValue) { pass = Retrieve(line, out result); if (pass && validationMethod != null) pass = validationMethod(result); } else { if (line != "") { pass = Retrieve(line, out result); if (pass && validationMethod != null) pass = validationMethod(result); } else { pass = true; result = defaultValue; } } if (!pass) { Console.WriteLine("Invalid value [{0}]", line); if (failureMessage != null) { if (!requireValue) Console.Write(string.Format(failureMessage + " [{0}]: ", defaultValue)); else Console.Write(failureMessage + ": "); } else { if (!requireValue) Console.Write(string.Format(message + " [{0}]: ", defaultValue)); else Console.Write(message + ": "); } } } return result; } private static bool Retrieve<T>(string line, out T resultValue) where T : struct { var type = typeof(T); resultValue = default(T); bool pass = false; if (type == typeof(short)) { short result = 0; pass = short.TryParse(line, out result); resultValue = (T)(object)result; } else if (type == typeof(int)) { int result = 0; pass = int.TryParse(line, out result); resultValue = (T)(object)result; } else if (type == typeof(float)) { float result = 0f; pass = float.TryParse(line, out result); resultValue = (T)(object)result; } else if (type == typeof(double)) { double result = 0f; pass = double.TryParse(line, out result); resultValue = (T)(object)result; } else if (type == typeof(sbyte)) { sbyte result = 0; pass = sbyte.TryParse(line, out result); resultValue = (T)(object)result; } else if (type == typeof(byte)) { byte result = 0; pass = byte.TryParse(line, out result); resultValue = (T)(object)result; } else if (type == typeof(ushort)) { ushort result = 0; pass = ushort.TryParse(line, out result); resultValue = (T)(object)result; } else if (type == typeof(uint)) { uint result = 0; pass = uint.TryParse(line, out result); resultValue = (T)(object)result; } else if (type == typeof(long)) { long result = 0; pass = long.TryParse(line, out result); resultValue = (T)(object)result; } else if (type == typeof(ulong)) { ulong result = 0; pass = ulong.TryParse(line, out result); resultValue = (T)(object)result; } return pass; } Additional notes: if anyone would like to use this in your projects, you are more than welcome to.