So I wrote this for my [Mandelbrot Generator](http://codereview.stackexchange.com/questions/104171/multithreaded-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**.