When .NET 2.0 was released, a TryParse() method was added to many value types such as Int32, DataTime, etc. This was a huge improvement because there was no longer a need to catch expensive exceptions and drag down performance. However, one drawback of the TryParse() method is that the syntax is a little clunky. The most common example looks like this:
Person person = new Person(); string value = "21"; int num; int.TryParse(value, out num); person.Age = num;
So it's great that we can do all this without having to catch exceptions but it definitely seems more complex than it has to be given that all we're trying to do is assign an integer to the Age property and we need this many lines of code. We can use Extension methods to make the consuming code much more friendly - a single line of code:
person.Age = value.TryParseInt32();
To implement the static class for the extension methods, we could implement each TryParseXX() method like this:
public static int TryParseInt32(this string value) { int result; int.TryParse(value, out result); return result; }
However, now we've got the ugly, repetitive code in numerous methods inside that class. On the good side, at least we've encapsulated the repetitive code inside a single class, but we can leverage a generic delegate and generic method to even avoid the repetition inside that class.
private delegate bool ParseDelegate<T>(string s, out T result); private static T TryParse<T>(this string value, ParseDelegate<T> parse) where T : struct { T result; parse(value, out result); return result; }
This allows our TryParseInt32() implementation to now be a single line of code:
public static int TryParseInt32(this string value) { return TryParse<int>(value, int.TryParse); }
The ParseDelegate
public static class TryParseExtensions { public static int TryParseInt32(this string value) { return TryParse<int>(value, int.TryParse); } public static Int16 TryParseInt16(this string value) { return TryParse<Int16>(value, Int16.TryParse); } public static Int64 TryParseInt64(this string value) { return TryParse<Int64>(value, Int64.TryParse); } public static byte TryParseByte(this string value) { return TryParse<byte>(value, byte.TryParse); } public static bool TryParseBoolean(this string value) { return TryParse<bool>(value, bool.TryParse); } public static Single TryParseSingle(this string value) { return TryParse<Single>(value, Single.TryParse); } public static Double TryParseDoube(this string value) { return TryParse<Double>(value, Double.TryParse); } public static Decimal TryParseDecimal(this string value) { return TryParse<Decimal>(value, Decimal.TryParse); } public static DateTime TryParseDateTime(this string value) { return TryParse<DateTime>(value, DateTime.TryParse); } #region Private Members private delegate bool ParseDelegate<T>(string s, out T result); private static T TryParse<T>(this string value, ParseDelegate<T> parse) where T : struct { T result; parse(value, out result); return result; } #endregion }