49

But here's an example:

Dim desiredType as Type
if IsNumeric(desiredType) then ...

EDIT: I only know the Type, not the Value as a string.

Ok, so unfortunately I have to cycle through the TypeCode.

But this is a nice way to do it:

 if ((desiredType.IsArray))
      return 0;

 switch (Type.GetTypeCode(desiredType))
 {
      case 3:
      case 6:
      case 7:
      case 9:
      case 11:
      case 13:
      case 14:
      case 15:
          return 1;
 }
 ;return 0;
ThinkingStiff
  • 64,767
  • 30
  • 146
  • 239
Nescio
  • 27,645
  • 10
  • 53
  • 72
  • A few years late here, but why does IsArray matter? An Array is an Object and should fail your switch. – Suraj Mar 03 '11 at 15:21

10 Answers10

105

A few years late here, but here's my solution (you can choose whether to include boolean). Solves for the Nullable case. XUnit test included

/// <summary>
/// Determines if a type is numeric.  Nullable numeric types are considered numeric.
/// </summary>
/// <remarks>
/// Boolean is not considered numeric.
/// </remarks>
public static bool IsNumericType( Type type )
{
    if (type == null)
    {
        return false;
    }

    switch (Type.GetTypeCode(type))
    {
        case TypeCode.Byte:
        case TypeCode.Decimal:
        case TypeCode.Double:
        case TypeCode.Int16:
        case TypeCode.Int32:
        case TypeCode.Int64:
        case TypeCode.SByte:
        case TypeCode.Single:
        case TypeCode.UInt16:
        case TypeCode.UInt32:
        case TypeCode.UInt64:
            return true;
        case TypeCode.Object:
            if ( type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
               return IsNumericType(Nullable.GetUnderlyingType(type));
            }
            return false;
    }
    return false;
}



/// <summary>
/// Tests the IsNumericType method.
/// </summary>
[Fact]
public void IsNumericTypeTest()
{
    // Non-numeric types
    Assert.False(TypeHelper.IsNumericType(null));
    Assert.False(TypeHelper.IsNumericType(typeof(object)));
    Assert.False(TypeHelper.IsNumericType(typeof(DBNull)));
    Assert.False(TypeHelper.IsNumericType(typeof(bool)));
    Assert.False(TypeHelper.IsNumericType(typeof(char)));
    Assert.False(TypeHelper.IsNumericType(typeof(DateTime)));
    Assert.False(TypeHelper.IsNumericType(typeof(string)));

    // Arrays of numeric and non-numeric types
    Assert.False(TypeHelper.IsNumericType(typeof(object[])));
    Assert.False(TypeHelper.IsNumericType(typeof(DBNull[])));
    Assert.False(TypeHelper.IsNumericType(typeof(bool[])));
    Assert.False(TypeHelper.IsNumericType(typeof(char[])));
    Assert.False(TypeHelper.IsNumericType(typeof(DateTime[])));
    Assert.False(TypeHelper.IsNumericType(typeof(string[])));
    Assert.False(TypeHelper.IsNumericType(typeof(byte[])));
    Assert.False(TypeHelper.IsNumericType(typeof(decimal[])));
    Assert.False(TypeHelper.IsNumericType(typeof(double[])));
    Assert.False(TypeHelper.IsNumericType(typeof(short[])));
    Assert.False(TypeHelper.IsNumericType(typeof(int[])));
    Assert.False(TypeHelper.IsNumericType(typeof(long[])));
    Assert.False(TypeHelper.IsNumericType(typeof(sbyte[])));
    Assert.False(TypeHelper.IsNumericType(typeof(float[])));
    Assert.False(TypeHelper.IsNumericType(typeof(ushort[])));
    Assert.False(TypeHelper.IsNumericType(typeof(uint[])));
    Assert.False(TypeHelper.IsNumericType(typeof(ulong[])));

    // numeric types
    Assert.True(TypeHelper.IsNumericType(typeof(byte)));
    Assert.True(TypeHelper.IsNumericType(typeof(decimal)));
    Assert.True(TypeHelper.IsNumericType(typeof(double)));
    Assert.True(TypeHelper.IsNumericType(typeof(short)));
    Assert.True(TypeHelper.IsNumericType(typeof(int)));
    Assert.True(TypeHelper.IsNumericType(typeof(long)));
    Assert.True(TypeHelper.IsNumericType(typeof(sbyte)));
    Assert.True(TypeHelper.IsNumericType(typeof(float)));
    Assert.True(TypeHelper.IsNumericType(typeof(ushort)));
    Assert.True(TypeHelper.IsNumericType(typeof(uint)));
    Assert.True(TypeHelper.IsNumericType(typeof(ulong)));

    // Nullable non-numeric types
    Assert.False(TypeHelper.IsNumericType(typeof(bool?)));
    Assert.False(TypeHelper.IsNumericType(typeof(char?)));
    Assert.False(TypeHelper.IsNumericType(typeof(DateTime?)));

    // Nullable numeric types
    Assert.True(TypeHelper.IsNumericType(typeof(byte?)));
    Assert.True(TypeHelper.IsNumericType(typeof(decimal?)));
    Assert.True(TypeHelper.IsNumericType(typeof(double?)));
    Assert.True(TypeHelper.IsNumericType(typeof(short?)));
    Assert.True(TypeHelper.IsNumericType(typeof(int?)));
    Assert.True(TypeHelper.IsNumericType(typeof(long?)));
    Assert.True(TypeHelper.IsNumericType(typeof(sbyte?)));
    Assert.True(TypeHelper.IsNumericType(typeof(float?)));
    Assert.True(TypeHelper.IsNumericType(typeof(ushort?)));
    Assert.True(TypeHelper.IsNumericType(typeof(uint?)));
    Assert.True(TypeHelper.IsNumericType(typeof(ulong?)));

    // Testing with GetType because of handling with non-numerics. See:
    // http://msdn.microsoft.com/en-us/library/ms366789.aspx

    // Using GetType - non-numeric
    Assert.False(TypeHelper.IsNumericType((new object()).GetType()));
    Assert.False(TypeHelper.IsNumericType(DBNull.Value.GetType()));
    Assert.False(TypeHelper.IsNumericType(true.GetType()));
    Assert.False(TypeHelper.IsNumericType('a'.GetType()));
    Assert.False(TypeHelper.IsNumericType((new DateTime(2009, 1, 1)).GetType()));
    Assert.False(TypeHelper.IsNumericType(string.Empty.GetType()));

    // Using GetType - numeric types
    // ReSharper disable RedundantCast
    Assert.True(TypeHelper.IsNumericType((new byte()).GetType()));
    Assert.True(TypeHelper.IsNumericType(43.2m.GetType()));
    Assert.True(TypeHelper.IsNumericType(43.2d.GetType()));
    Assert.True(TypeHelper.IsNumericType(((short)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((int)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((long)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((sbyte)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(2f.GetType()));
    Assert.True(TypeHelper.IsNumericType(((ushort)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((uint)2).GetType()));
    Assert.True(TypeHelper.IsNumericType(((ulong)2).GetType()));
    // ReSharper restore RedundantCast

    // Using GetType - nullable non-numeric types
    bool? nullableBool = true;
    Assert.False(TypeHelper.IsNumericType(nullableBool.GetType()));
    char? nullableChar = ' ';
    Assert.False(TypeHelper.IsNumericType(nullableChar.GetType()));
    DateTime? nullableDateTime = new DateTime(2009, 1, 1);
    Assert.False(TypeHelper.IsNumericType(nullableDateTime.GetType()));

    // Using GetType - nullable numeric types
    byte? nullableByte = 12;
    Assert.True(TypeHelper.IsNumericType(nullableByte.GetType()));
    decimal? nullableDecimal = 12.2m;
    Assert.True(TypeHelper.IsNumericType(nullableDecimal.GetType()));
    double? nullableDouble = 12.32;
    Assert.True(TypeHelper.IsNumericType(nullableDouble.GetType()));
    short? nullableInt16 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableInt16.GetType()));
    short? nullableInt32 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableInt32.GetType()));
    short? nullableInt64 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableInt64.GetType()));
    sbyte? nullableSByte = 12;
    Assert.True(TypeHelper.IsNumericType(nullableSByte.GetType()));
    float? nullableSingle = 3.2f;
    Assert.True(TypeHelper.IsNumericType(nullableSingle.GetType()));
    ushort? nullableUInt16 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableUInt16.GetType()));
    ushort? nullableUInt32 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableUInt32.GetType()));
    ushort? nullableUInt64 = 12;
    Assert.True(TypeHelper.IsNumericType(nullableUInt64.GetType()));
}
Neo
  • 4,145
  • 6
  • 53
  • 76
Suraj
  • 35,905
  • 47
  • 139
  • 250
  • 4
    To add to this gravediggery, if you're going to define IsNumericType to take a type, why not recursively pass the result of Nullable.GetUnderlyingType to the same function and return its value? – lsuarez May 23 '11 at 21:16
  • yup...great suggestion. more elegant that way. updated post. – Suraj May 24 '11 at 16:23
  • 5
    why not declare this method in a static class and make it available to Type: `public static bool IsNumeric(this Type type) { /*...*/ }` ? – cimnine Nov 01 '12 at 14:11
  • Nullable.GetUnderlyingType() returns null if the type argument is not a nullable value. So I don't think you need to check IsGenericType and GetGenericTypeDefinition(). – Jack Feb 18 '13 at 00:24
  • 3
    Nice solution and also +1 for tests. Definitely better than accepted answer. – Marko Gresak Aug 30 '13 at 07:20
  • Nice solution. I'm trying to rework some code that uses this into a portable library (PCL). Depending on the profile used, the TypeCode enum and GetTypeCode() are not available. Wish there was another way that would work in the PCL! – Nate Rickard Nov 21 '13 at 17:03
  • 3
    Nice solution, just be aware that an Enum would be classified as an integer using the above logic – Joseph Caruana Mar 16 '15 at 12:46
  • I cant believe among all those tests you didn't include an enum type, even if you believe enum should be classified as a numeric type. Note that MS in its implementation doesnt consider enum as numeric type (in my answer) but I do think MS's other decision like char is numeric while decimal is not is flawed. Todd Menier has the best answer here which combines all the good parts and leaves out the oddities: http://stackoverflow.com/a/31709198/661933 – nawfal Jul 29 '15 at 20:18
  • @nawfal - good catch on enum. thanks for the link to Todd's answer. – Suraj Aug 03 '15 at 00:26
28

You can find out if a variable is numeric using the Type.GetTypeCode() method:

TypeCode typeCode = Type.GetTypeCode(desiredType);

if (typeCode == TypeCode.Double || typeCode == TypeCode.Integer || ...)
     return true;

You'll need to complete all the available numeric types in the "..." part ;)

More details here: TypeCode Enumeration

Jason Bunting
  • 58,249
  • 14
  • 102
  • 93
Jon Limjap
  • 94,284
  • 15
  • 101
  • 152
  • I was hoping I wouldn't have to check every type, but this works thanks! – Nescio Sep 23 '08 at 23:05
  • FYI, this code will not work if they're nullable types. In that case, the typecode returns as Object. Still trying to figure out how to get around that. Anyone? – Codewerks Dec 03 '09 at 13:00
  • 2
    Better: Foreach (TypeCode typecode in new TypeCode[] { TypeCode.Double [...] } if typecode == Type.GetTypeCode(desiredType) return true; return false; – tsilb Jul 09 '10 at 20:33
  • 2
    why couldn't you guys just do it for us so we can copy/paste? – Timmerz Jun 12 '13 at 15:24
  • Why use `TypeCode`? In C# we could use `if ((desiredType is double) || (desiredType is int) || ... ) return true;`, right? – Ben Jul 15 '14 at 11:31
  • 1
    @Ben, you can do "if (1 is int)" in C#, not "if (1.GetType() is int)". I hope you get the idea. – nawfal Jul 29 '15 at 20:09
7

Great article here Exploring IsNumeric for C#.

Option 1:

Reference Microsoft.VisualBasic.dll, then do the following:

if (Microsoft.VisualBasic.Information.IsNumeric("5"))
{
 //Do Something
}

Option 2:

public static bool Isumeric (object Expression)
{
    bool f;
    ufloat64 a;
    long l;

    IConvertible iConvertible = null;
    if ( ((Expression is IConvertible)))
    {
       iConvertible = (IConvertible) Expression;
    }

    if (iConvertible == null)
{
   if ( ((Expression is char[])))
   {
       Expression = new String ((char[]) Expression);
       goto IL_002d; // hopefully inserted by optimizer
   }
   return 0;
}
IL_002d:
TypeCode typeCode = iConvertible.GetTypeCode ();
if ((typeCode == 18) || (typeCode == 4))
{
    string str = iConvertible.ToString (null);
   try
   {
        if ( (StringType.IsHexOrOctValue (str, l)))
   {
        f = true;
        return f;
   }
}
catch (Exception )
{
    f = false;
    return f;
};
return DoubleType.TryParse (str, a);
}
return Utils.IsNumericTypeCode (typeCode);
}

internal static bool IsNumericType (Type typ)
{
bool f;
TypeCode typeCode;
if ( (typ.IsArray))
{
    return 0;
}
switch (Type.GetTypeCode (typ))
{
case 3: 
case 6: 
case 7: 
case 9: 
case 11: 
case 13: 
case 14: 
case 15: 
   return 1;
};
return 0;
}
hspain
  • 17,528
  • 5
  • 19
  • 31
Jorge Ferreira
  • 96,051
  • 25
  • 122
  • 132
6

With all due credit to @SFun28 and @nawfal (thanks!), I used both of their answers, tweaked slightly and came up with these extension methods:

public static class ReflectionExtensions
{
    public static bool IsNullable(this Type type) {
        return
            type != null &&
            type.IsGenericType && 
            type.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

    public static bool IsNumeric(this Type type) {
        if (type == null || type.IsEnum)
            return false;

        if (IsNullable(type))
            return IsNumeric(Nullable.GetUnderlyingType(type));

        switch (Type.GetTypeCode(type)) {
            case TypeCode.Byte:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.SByte:
            case TypeCode.Single:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
                return true;
            default:
                return false;
        }
    }
}
Todd Menier
  • 37,557
  • 17
  • 150
  • 173
5

I know this is a VERY late answer, but here is the function I use:

public static bool IsNumeric(Type type)
{
    var t = Nullable.GetUnderlyingType(type) ?? type;
    return t.IsPrimitive || t == typeof(decimal);
}

If you wanted to exclude char as a numeric type then you can use this example:

return (t.IsPrimitive || t == typeof(decimal)) && t != typeof(char);

According to the MSDN:

The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single.

Note: This check includes IntPtr and UIntPtr.

Here is the same function as a generic extension method (I know this doesn't work for the OP's case, but someone else might find it useful):

public static bool IsNumeric<T>(this T value)
{
    var t = Nullable.GetUnderlyingType(value.GetType()) ?? value.GetType();
    return t.IsPrimitive || t == typeof(decimal);
}
Josh T.
  • 151
  • 2
  • 10
5

If you have a reference to an actual object, here's a simple solution for C# that's very straightforward:

    /// <summary>
    /// Determines whether the supplied object is a .NET numeric system type
    /// </summary>
    /// <param name="val">The object to test</param>
    /// <returns>true=Is numeric; false=Not numeric</returns>
    public static bool IsNumeric(ref object val)
    {
        if (val == null)
            return false;

        // Test for numeric type, returning true if match
        if 
            (
            val is double || val is float || val is int || val is long || val is decimal || 
            val is short || val is uint || val is ushort || val is ulong || val is byte || 
            val is sbyte
            )
            return true;

        // Not numeric
        return false;
    }
Mark Jones
  • 2,024
  • 1
  • 19
  • 12
3

This is how MS has implemented it in System.Dynamic.Utils.TypeUtils which is an internal class. Turns out that they dont consider System.Decimal to be a numeric type (Decimal is omitted from enumeration). And interestingly MS finds System.Char type to be numeric. Otherwise it's exactly the same as SFun28's answer. I suppose his answer is "more correct".

internal static bool IsNumeric(Type type)
{
    type = type.GetNonNullableType();
    if (!type.IsEnum)
    {
        switch (Type.GetTypeCode(type))
        {
        case TypeCode.Char:
        case TypeCode.SByte:
        case TypeCode.Byte:
        case TypeCode.Int16:
        case TypeCode.UInt16:
        case TypeCode.Int32:
        case TypeCode.UInt32:
        case TypeCode.Int64:
        case TypeCode.UInt64:
        case TypeCode.Single:
        case TypeCode.Double:
            return true;
        }
    }
    return false;
}

//where GetNonNullableType is defined as

internal static Type GetNonNullableType(this Type type)
{
    if (type.IsNullableType())
    {
        return type.GetGenericArguments()[0];
    }
    return type;
}

//where IsNullableType is defined as

internal static bool IsNullableType(this Type type)
{
    return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
nawfal
  • 70,104
  • 56
  • 326
  • 368
1
''// Return true if a type is a numeric type.
Private Function IsNumericType(ByVal this As Type) As Boolean
    ''// All the numeric types have bits 11xx set whereas non numeric do not.
    ''// That is if you include char type which is 4(decimal) = 100(binary).
    If this.IsArray Then Return False
    If (Type.GetTypeCode(this) And &HC) > 0 Then Return True
    Return False
End Function
Michael Haren
  • 105,752
  • 40
  • 168
  • 205
Mike
  • 43
  • 1
1

You can now use the .NET Framework method

typeof(decimal?).IsNumericType()
labilbe
  • 3,501
  • 2
  • 29
  • 34
-5

Use Type.IsValueType() and TryParse():

public bool IsInteger(Type t)
{
   int i;
   return t.IsValueType && int.TryParse(t.ToString(), out i);
}
Mike Post
  • 6,355
  • 3
  • 38
  • 48
  • 1
    "t" is not a variable of the Type in question. It *is* the type in question. t will never be a number in this code. – Scott Isaacs Apr 24 '10 at 03:01