2008-09-23 16 views
45

Pero aquí está un ejemplo:Usando .Net, ¿cómo puedo determinar si un tipo es un ValueType numérico?

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

EDIT: que sólo conoce el tipo, no el valor como una cadena.

Ok, así que desafortunadamente tengo que pasar por el TypeCode.

Pero esta es una buena manera de hacerlo:

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; 
+0

unos años tarde aquí, pero ¿por qué ¿Importa IsArray? Una matriz es un objeto y debe fallar su cambio. – SFun28

Respuesta

95

Hace algunos años, pero esta es mi solución (puede elegir si desea incluir booleano). Resuelve para el caso Nullable. prueba XUnit incluido

/// <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())); 
} 
+3

Agregar Para esta gran obra, si va a definir IsNumericType para tomar un tipo, ¿por qué no pasar recursivamente el resultado de Nullable.GetUnderlyingType a la misma función y devolver su valor? – lsuarez

+0

yup ... gran sugerencia. más elegante de esa manera. publicación actualizada. – SFun28

+4

¿por qué no declarar este método en una clase estática y ponerlo a disposición para Tipo: 'bool estático público IsNumeric (este tipo de tipo) {/*...*/}'? – cimnine

28

Usted puede averiguar si una variable es numérica mediante el método de Type.GetTypeCode():

TypeCode typeCode = Type.GetTypeCode(desiredType); 

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

que necesitará para completar todo el tipos numéricos disponibles en el "..."); parte

más detalles aquí: TypeCode Enumeration

+0

¡Tenía la esperanza de no tener que verificar todos los tipos, pero esto funciona gracias! – Nescio

+0

FYI, este código no funcionará si son tipos anulables. En ese caso, el typecode regresa como Object. Todavía estoy tratando de encontrar la forma de evitar eso. ¿Nadie? – Codewerks

+2

Mejor: Foreach (código de tipo TypeCode en el nuevo TypeCode [] {TypeCode.Double [...]} si typecode == Type.GetTypeCode (desiredType) return true; return false; – tsilb

7

Gran artículo aquí Exploring IsNumeric for C#.

Opción 1:

Referencia Microsoft.VisualBasic.dll, a continuación, hacer lo siguiente:

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

Opción 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; 
} 
-5

Uso Type.IsValueType() y TryParse():

public bool IsInteger(Type t) 
{ 
    int i; 
    return t.IsValueType && int.TryParse(t.ToString(), out i); 
} 
+1

"t" no es una variable del tipo en pregunta. * es * el tipo en cuestión. t nunca será un número en este código. –

2
''// 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 
+0

Si esto es cierto, esta es una mejor respuesta WAAAAY, ¡Dios! – toddmo

+0

Totalmente erróneo, SByte es numérico y tiene una identificación de 5, que es '0101', entonces esto es incorrecto. – Gusman

5

Si usted tiene una referencia a un objeto real, he aquí una solución simple para C# que es muy sencillo:

/// <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; 
    } 
+1

Se me ocurrió algo similar. ¿Puedo preguntar por qué está utilizando la palabra clave "ref" con el argumento val? –

+0

Esto es lo mismo que las soluciones basadas en código de tipo anteriores, excepto que es más lento ... –

3

Esta es la forma en la EM ha implementado en System.Dynamic.Utils.TypeUtils que es un interno clase. Resulta que no consideran System.Decimal como un tipo numérico (Decimal se omite de la enumeración). Y curiosamente MS encuentra que el tipo System.Char es numérico. De lo contrario, es exactamente lo mismo que la respuesta de SFun28. Supongo que su respuesta es "más correcta".

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<>); 
} 
+0

Me pregunto si hay una manera de optimizar aún más esto usando operaciones de bits y otras cosas ... –

4

Con el debido crédito a @ SFun28 y @nawfal (gracias!), He utilizado tanto de sus respuestas, pellizcado levemente y se acercó con estos métodos de extensión:

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; 
     } 
    } 
} 
+0

no entiendo por qué si 'tipo. IsEnum 'devuelve falso? – Riga

+2

@Riga Pude ver que las enumeraciones eran un área gris, pero me equivocaba al lado de las falsas. Supongamos que está creando un serializador JSON y quiere que las enumeraciones se serialicen en cadenas. En ese caso, no querrás tratarlos como un número. –

3

Sé que esto es una respuesta muy tarde, pero aquí es la función que utilizo:

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

Si quería excluir char como un tipo numérico, puede utilizar este ejemplo:

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

According to the MSDN:

Los tipos primitivos son Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double y Single.

Nota: Este control incluye IntPtr y UIntPtr.

aquí es la misma función que un método de extensión genérica (sé que esto no funciona para el caso de la OP, pero otra persona puede resultar útil):

public static bool IsNumeric<T>(this T value) 
{ 
    var t = Nullable.GetUnderlyingType(value.GetType()) ?? value.GetType(); 
    return t.IsPrimitive || t == typeof(decimal); 
} 
Cuestiones relacionadas