Don't overlook that .NET includes Microsoft.VisualBasic.Information.IsNumeric() which can be used from C# just as well as VB. This may be preferable to writing your own, or at least use it as a basis.
The way it works is to first look for certain types that can be "converted" to or parsed as numbers (strings, chars, or char arrays), and then finally just checks the type code to see if it is one of the intrinsic numeric types.
If you want to exclude strings or chars then you could use it like so:
if (foo.GetType().IsValueType && !(foo is char) && Information.IsNumeric(foo))
{
// Numeric...
}
Reference source does not seem to include this, but it can be viewed in Visual Studio:
public static bool IsNumeric(object Expression)
{
IConvertible convertible = Expression as IConvertible;
if (convertible == null)
{
char[] array = Expression as char[];
if (array == null)
{
return false;
}
Expression = new string(array);
}
TypeCode typeCode = convertible.GetTypeCode();
if (typeCode == TypeCode.String || typeCode == TypeCode.Char)
{
string value = convertible.ToString(null);
try
{
long i64Value = default(long);
if (Utils.IsHexOrOctValue(value, ref i64Value))
{
return true;
}
}
catch (StackOverflowException ex) { throw ex; }
catch (OutOfMemoryException ex2) { throw ex2; }
catch (ThreadAbortException ex3) { throw ex3; }
catch (Exception) { return false; }
double Result = default(double);
return DoubleType.TryParse(value, ref Result);
}
return IsOldNumericTypeCode(typeCode);
}
They way it checks for explicit numeric types is similar to answer https://stackoverflow.com/a/18857243/3195477 although its logic is inverted in a way which may be more robust/safe: it only returns true
for a known numeric type, as opposed to returning false
for known non-numeric types; the latter could lead to a bug if ever other types are added.
internal static bool IsOldNumericTypeCode(TypeCode TypCode)
{
switch (TypCode)
{
case TypeCode.Boolean:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
default:
return false;
}
}