It's funny you should mention it because I was messing around with something just like this the other day:
using System;
using System.Reflection;
static class Example
{
public static Tuple<Boolean, T?> TryParse<T>(this String candidate)
where T : struct
{
T? value = null;
Boolean success = false;
var parser = ParsingBinder<T>.GetParser();
try
{
value = parser(candidate);
success = true;
}
catch (FormatException) { }
return new Tuple<Boolean,T?>(success, value);
}
}
static class ParsingBinder<T>
{
static Func<String, T> parser;
public static Func<String, T> GetParser()
{
if (parser == null)
parser = getParser();
return parser;
}
static Func<String, T> getParser()
{
MethodInfo methodInfo
= typeof(T).GetMethod(
"Parse", new [] { typeof(String) });
if (methodInfo == null)
throw new Exception(
"Unable to retrieve a \"Parse\" method for type.");
return (Func<String, T>)Delegate
.CreateDelegate(typeof(Func<String, T>), methodInfo);
}
}
It is a similar approach but think of it like a better TryParse
method that returns a Tuple<Boolean, T?>
(this requires .NET 4). The first property of the tuple is a boolean value indicating the success or failure of the parsing attempt and the second property is a nullable value typed to the generic type argument that will be null
if parsing fails and the value if parsing succeeds.
It works by using reflection to retrieve a static Parse(String)
method from the generic type argument and invokes that method for the string that is passed in. I built it as an extension method to allow you to do stuff like this:
var intValue = "1234".TryParse<Int32>();
var doubleValue = "1234".TryParse<Double>();
Unfortunately this won't work on enums
since they don't have the same signature for the parse method so you couldn't use this extension to parse an enum
but it wouldn't be hard to hack this up to make a special case for enums.
One of the nice things about this approach is that the cost of retrieving the Parse
method via reflection is only incurred on the first use since a static delegate is created for all subsequent uses.
One more thing - the only thing that is clunky about this approach is that there is no language extensions or syntactic sugar that would make this easy to work with. What I was hoping to achieve with this code was a less clunky way of using the standard TryParse
methods that exist in the BCL.
I personally find this pattern rather ugly:
Int32 value;
if (Int32.TryParse(someString, out value))
// do something with value
mainly because it requires a variable declaration ahead of time and the use of an out
parameter. My approach above isn't really that much better:
var result = someString.TryParse<Int32>();
if (result.Item1)
// do something with result.Item2
What would be really cool would be to see a C# language extension that was built to work with a Tuple<Boolean, T?>
that would allow us to work with this type smoothly but I get the feeling the more I write about this that it doesn't really seem that feasible.