Sunday, November 29, 2009

TryParse for the Compact Framework

One of the annoying things about the Compact Framework is that it doesn’t contain the TryParse methods that are found in the full framework.

At the company I work for we have some applications and common libraries that have both compact and full framework versions. Rather than repeat the code in each, we share the class files between the two projects (full/compact versions) and use conditional compilation where necessary to alter the code to match one framework or the other… unfortunately there isn’t a good and simple solution for the missing TryParse methods.

In theory it is possible to write your own functionally correct TryParse methods, but I haven’t yet done this (I intend to eventually). What I have done, in the meantime, to allow our code to compile is created a static ParseAssistant class. This class has static method overloads for all the usual TryParse methods we use, and our developers have been told to use these methods instead of the normal .NET ones. This means their code will compile on either framework… the only downside is that because I haven’t yet written ‘proper’ try parse code I have just conditionally compiled in (for the compact framework) a Parse with exception handling to report if the parse failed. This isn’t performant, but only applies in the compact framework and is easily rectified at a later time when it becomes a problem. In the meantime, should anyone else have the same problem here is the code we’re currently using;

/// <summary>
/// Contains methods to assist with parsing one value into another.
/// </summary>
public static class ParseAssistant
{
  #region TryParse Overloads
  /// <summary>
  /// Attempts to parse the string provided into an integer value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out int result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = Convert.ToInt32(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = int.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into a byte value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out byte result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = Convert.ToByte(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = byte.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into an Int16 value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out Int16 result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = Convert.ToInt16(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = Int16.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into an Int64 value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out Int64 result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = Convert.ToInt64(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = Int64.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into a decimal value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out decimal result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = Convert.ToDecimal(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = decimal.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into a float value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out float result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = (float)Convert.ToDecimal(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = float.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into a double value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out double result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = Convert.ToDouble(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = double.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into an sbyte value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out sbyte result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = (sbyte)Convert.ToInt32(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = sbyte.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into a uint value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out uint result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = (uint)Convert.ToUInt64(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = uint.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into a ulong value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out ulong result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = (ulong)Convert.ToUInt64(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = ulong.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into a ushort value. 
  /// </summary>
  /// <remarks>Returns 0 in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or zero if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out ushort result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = (ushort)Convert.ToUInt64(s);
            retVal = true;
        }
        catch (FormatException) { result = 0; }
        catch (InvalidCastException) { result = 0; }
#else
    retVal = ushort.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into an <see cref="System.DateTime"/> value. 
  /// </summary>
  /// <remarks>Returns <see cref="System.DateTime.MinValue"/> in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or <see cref="System.DateTime.MinValue"/> if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out DateTime result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = Convert.ToDateTime(s);
            retVal = true;
        }
        catch (FormatException) { result = DateTime.MinValue; }
        catch (InvalidCastException) { result = DateTime.MinValue; }
#else
    retVal = DateTime.TryParse(s, out result);
#endif
    return retVal;
  }
  /// <summary>
  /// Attempts to parse the string provided into an integer value. 
  /// </summary>
  /// <remarks>Returns false in the result parameter if the parse fails.</remarks>
  /// <param name="s">The string to attempt to parse.</param>
  /// <param name="result">The result of the parsed string, or false if parsing failed.</param>
  /// <returns>A boolean value indicating whether or not the parse succeeded.</returns>
  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
  public static bool TryParse(string s, out bool result)
  {
    bool retVal = false;
#if WindowsCE
        try
        {
            result = Convert.ToBoolean(s);
            retVal = true;
        }
        catch (FormatException) { result = false; }
        catch (InvalidCastException) { result = false; }
#else
    retVal = bool.TryParse(s, out result);
#endif
    return retVal;
  }
  #endregion
}

You’ll need to add a ‘Conditional Compilation Symbol’ called WindowsCE to the project build properties of your compact framework projects for the conditional compilation to work correctly.


Obviously you could turn these into extension methods where supported, but as I work mostly in the .NET 2.0 framework I haven’t done this.






4 comments:

  1. I know this is kind of old but for your TryParse(string,double), Convert.ToDouble won't throw an exception when s is null, and it will return 0. So your TryParse will return true and result will be 0. The .NET TryParse actually returns false for s being null. It is a minor inconsistancy but could lead to problems.

    ReplyDelete
  2. Thanks for that info! A good implementation would be consistent, and I wasn't aware Convert.ToDouble didn't throw on nulls (I would have expected it to).

    ReplyDelete