C # – cómo determinar si un tipo es un número

¿Hay alguna manera de determinar si un tipo .Net dado es un número? Por ejemplo: System.UInt32/UInt16/Double son todos números. Quiero evitar una larga conmutación en el Type.FullName .

Prueba esto:

 Type type = object.GetType(); bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char)); 

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

Tomando la solución de Guillaume un poco más allá:

 public static bool IsNumericType(this object o) { switch (Type.GetTypeCode(o.GetType())) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Decimal: case TypeCode.Double: case TypeCode.Single: return true; default: return false; } } 

Uso:

 int i = 32; i.IsNumericType(); // True string s = "Hello World"; s.IsNumericType(); // False 

No use un interruptor, solo use un conjunto:

 HashSet NumericTypes = new HashSet { typeof(decimal), typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), ... }; 

EDITAR: Una ventaja de esto sobre el uso de un código de tipo es que cuando se introducen nuevos tipos numéricos en .NET (por ejemplo, BigInteger y Complex ) es fácil de ajustar, mientras que esos tipos no obtendrán un código de tipo.

Ninguna de las soluciones tiene en cuenta Nullable.

Modifiqué un poco la solución de Jon Skeet:

  private static HashSet NumericTypes = new HashSet { typeof(int), typeof(uint), typeof(double), typeof(decimal), ... }; internal static bool IsNumericType(Type type) { return NumericTypes.Contains(type) || NumericTypes.Contains(Nullable.GetUnderlyingType(type)); } 

Sé que podría agregar los nulables a mi HashSet. Pero esta solución evita el peligro de olvidarse de agregar un Nullable específico a su lista.

  private static HashSet NumericTypes = new HashSet { typeof(int), typeof(int?), ... }; 
 public static bool IsNumericType(Type type) { switch (Type.GetTypeCode(type)) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Decimal: case TypeCode.Double: case TypeCode.Single: return true; default: return false; } } 

Nota sobre la optimización eliminada (ver comentarios de enzi) Y si realmente quieres optimizarla (perder legibilidad y algo de seguridad …):

 public static bool IsNumericType(Type type) { TypeCode typeCode = Type.GetTypeCode(type); //The TypeCode of numerical types are between SByte (5) and Decimal (15). return (int)typeCode >= 5 && (int)typeCode <= 15; } 

Básicamente es la solución de Skeet pero puedes reutilizarla con tipos Nullable de la siguiente manera:

 public static class TypeHelper { private static readonly HashSet NumericTypes = new HashSet { typeof(int), typeof(double), typeof(decimal), typeof(long), typeof(short), typeof(sbyte), typeof(byte), typeof(ulong), typeof(ushort), typeof(uint), typeof(float) }; public static bool IsNumeric(Type myType) { return NumericTypes.Contains(Nullable.GetUnderlyingType(myType) ?? myType); } } 

Enfoque basado en la propuesta de Philip , mejorado con el cheque de tipo interno de Nullable para tipos Nullable :

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

¿Por qué esto? Tuve que verificar si un Type type es un tipo numérico, y no si un object o arbitrario object o es numérico.

Puede usar Type.IsPrimitive y luego ordenar los tipos Boolean y Char , algo como esto:

 bool IsNumeric(Type type) { return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool); } 

EDITAR : También puede excluir los tipos IntPtr y UIntPtr , si no los considera numéricos.

Con C # 7, este método me proporciona un mejor rendimiento que la caja del interruptor en TypeCode y HashSet :

 public static bool IsNumeric(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is float || o is double || o is decimal; 

Las pruebas son las siguientes:

 public static class Extensions { public static HashSet NumericTypes = new HashSet() { typeof(byte), typeof(sbyte), typeof(ushort), typeof(uint), typeof(ulong), typeof(short), typeof(int), typeof(long), typeof(decimal), typeof(double), typeof(float) }; public static bool IsNumeric1(this object o) => NumericTypes.Contains(o.GetType()); public static bool IsNumeric2(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is decimal || o is double || o is float; public static bool IsNumeric3(this object o) { switch (o) { case Byte b: case SByte sb: case UInt16 u16: case UInt32 u32: case UInt64 u64: case Int16 i16: case Int32 i32: case Int64 i64: case Decimal m: case Double d: case Single f: return true; default: return false; } } public static bool IsNumeric4(this object o) { switch (Type.GetTypeCode(o.GetType())) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Decimal: case TypeCode.Double: case TypeCode.Single: return true; default: return false; } } } class Program { static void Main(string[] args) { var count = 100000000; //warm up calls for (var i = 0; i < count; i++) { i.IsNumeric1(); } for (var i = 0; i < count; i++) { i.IsNumeric2(); } for (var i = 0; i < count; i++) { i.IsNumeric3(); } for (var i = 0; i < count; i++) { i.IsNumeric4(); } //Tests begin here var sw = new Stopwatch(); sw.Restart(); for (var i = 0; i < count; i++) { i.IsNumeric1(); } sw.Stop(); Debug.WriteLine(sw.ElapsedMilliseconds); sw.Restart(); for (var i = 0; i < count; i++) { i.IsNumeric2(); } sw.Stop(); Debug.WriteLine(sw.ElapsedMilliseconds); sw.Restart(); for (var i = 0; i < count; i++) { i.IsNumeric3(); } sw.Stop(); Debug.WriteLine(sw.ElapsedMilliseconds); sw.Restart(); for (var i = 0; i < count; i++) { i.IsNumeric4(); } sw.Stop(); Debug.WriteLine(sw.ElapsedMilliseconds); } 

Respuesta corta: No.

Respuesta más larga: No.

El hecho es que muchos tipos diferentes en C # pueden contener datos numéricos. A menos que sepa qué esperar (Int, Double, etc.), necesita usar la statement de caso “larga”.

Son todos los tipos de valor (a excepción de bool y quizás enum). Entonces podrías simplemente usar:

 bool IsNumberic(object o) { return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum)) } 

Esto también puede funcionar. Sin embargo, es posible que desee seguir con un Type.Parse para lanzarlo de la manera que desee después.

 public bool IsNumeric(object value) { float testValue; return float.TryParse(value.ToString(), out testValue); } 

Lamentablemente, estos tipos no tienen mucho en común, salvo que son todos tipos de valores. Pero para evitar un conmutador largo, puede definir una lista de solo lectura con todos estos tipos y luego simplemente verificar si el tipo dado está dentro de la lista.

Uy! ¡Leyó mal la pregunta! Personalmente, rodaría con Skeet’s .


hrm, parece que quiere hacer DoSomething en Type de sus datos. Lo que podrías hacer es lo siguiente

 public class MyClass { private readonly Dictionary> _map = new Dictionary> (); public MyClass () { _map.Add (typeof (int), o => return SomeTypeSafeMethod ((int)(o))); } public SomeResult DoSomething(T numericValue) { Type valueType = typeof (T); if (!_map.Contains (valueType)) { throw new NotSupportedException ( string.Format ( "Does not support Type [{0}].", valueType.Name)); } SomeResult result = _map[valueType] (numericValue); return result; } } 

Solución modificada de skeet y arviman utilizando Generics , Reflection y C# v6.0 .

 private static readonly HashSet m_numTypes = new HashSet { typeof(int), typeof(double), typeof(decimal), typeof(long), typeof(short), typeof(sbyte), typeof(byte), typeof(ulong), typeof(ushort), typeof(uint), typeof(float), typeof(BigInteger) }; 

Seguido por:

 public static bool IsNumeric( this T myType ) { var IsNumeric = false; if( myType != null ) { IsNumeric = m_numTypes.Contains( myType.GetType() ); } return IsNumeric; } 

Uso para (T item) :

 if ( item.IsNumeric() ) {} 

null devuelve falso.