Me gustaría comprobar si un objeto es un número para que .ToString()
daría lugar a una cadena que contiene dígitos y +
, -
,.
¿Es posible mediante una simple verificación de tipos en .net (como :) if (p is Number)
?
¿O debería convertir a una cadena y luego intentar analizar para duplicar?
Actualización: para aclarar que mi objeto es int, uint, float, double, etc., no es una cadena. Estoy tratando de hacer una función que serialice cualquier objeto a xml como este:
<string>content</string>
o
<numeric>123.3</numeric>
o plantear una excepción.
c#
.net
serialization
xml-serialization
Piotr Czapla
fuente
fuente
Respuestas:
Simplemente necesitará hacer una verificación de tipo para cada uno de los tipos numéricos básicos.
Aquí hay un método de extensión que debería hacer el trabajo:
public static bool IsNumber(this object value) { return value is sbyte || value is byte || value is short || value is ushort || value is int || value is uint || value is long || value is ulong || value is float || value is double || value is decimal; }
Esto debería cubrir todos los tipos numéricos.
Actualizar
Parece que realmente desea analizar el número de una cadena durante la deserialización. En este caso, probablemente sería mejor usarlo
double.TryParse
.string value = "123.3"; double num; if (!double.TryParse(value, out num)) throw new InvalidOperationException("Value is not a number.");
Por supuesto, esto no manejaría números enteros / decimales largos muy grandes, pero si ese es el caso, solo necesita agregar llamadas adicionales a
long.TryParse
/decimal.TryParse
/ cualquier otra cosa.fuente
Tomado del Blog de Scott Hanselman :
public static bool IsNumeric(object expression) { if (expression == null) return false; double number; return Double.TryParse( Convert.ToString( expression , CultureInfo.InvariantCulture) , System.Globalization.NumberStyles.Any , NumberFormatInfo.InvariantInfo , out number); }
fuente
double.Parse(double.MaxValue.ToString())
causa unOverflowException
. Puede remediar esto proporcionando el modificador de ida y vuelta.ToString("R")
en este caso, pero esa sobrecarga no está disponibleConvert.ToString(...)
ya que no conocemos el tipo. Sé que este es un caso marginal, pero me encontré con él mientras escribía pruebas para mi propia.IsNumeric()
extensión. Mi "solución" fue agregar un swtich de verificación de tipos antes de intentar analizar cualquier cosa, vea mi respuesta a esta pregunta para el código.Aproveche la propiedad IsPrimitive para crear un método de extensión útil:
public static bool IsNumber(this object obj) { if (Equals(obj, null)) { return false; } Type objType = obj.GetType(); objType = Nullable.GetUnderlyingType(objType) ?? objType; if (objType.IsPrimitive) { return objType != typeof(bool) && objType != typeof(char) && objType != typeof(IntPtr) && objType != typeof(UIntPtr); } return objType == typeof(decimal); }
EDITAR: Corregido según los comentarios. Los genéricos se eliminaron desde los tipos de valor de las cajas .GetType (). También se incluye una corrección para los valores que aceptan valores NULL.
fuente
object
ystring
no son tipos primitivos.Hay algunas buenas respuestas arriba. Aquí tienes una solución todo en uno. Tres sobrecargas para diferentes circunstancias.
// Extension method, call for any object, eg "if (x.IsNumeric())..." public static bool IsNumeric(this object x) { return (x==null ? false : IsNumeric(x.GetType())); } // Method where you know the type of the object public static bool IsNumeric(Type type) { return IsNumeric(type, Type.GetTypeCode(type)); } // Method where you know the type and the type code of the object public static bool IsNumeric(Type type, TypeCode typeCode) { return (typeCode == TypeCode.Decimal || (type.IsPrimitive && typeCode != TypeCode.Object && typeCode != TypeCode.Boolean && typeCode != TypeCode.Char)); }
fuente
En lugar de lanzar el suyo, la forma más confiable de saber si un tipo incorporado es numérico es probablemente hacer referencia
Microsoft.VisualBasic
y llamarInformation.IsNumeric(object value)
. La implementación maneja una serie de casos sutiles comochar[]
cadenas HEX y OCT.fuente
Allí hay tres conceptos diferentes:
is
- por ejemploif(obj is int) {...}
TryParse()
ToString()
puede dar algo que parece un número, entonces llámeloToString()
y trátelo como una cadenaEn los dos primeros casos, probablemente tendrá que manejar por separado cada tipo numérico que desee admitir (
double
/decimal
/int
); cada uno tiene diferentes rangos y precisión, por ejemplo.También puede mirar las expresiones regulares para una verificación rápida y preliminar.
fuente
Suponiendo que su entrada es una cadena ...
Hay 2 formas:
usar Double.TryParse ()
double temp; bool isNumber = Double.TryParse(input, out temp);
usar Regex
bool isNumber = Regex.IsMatch(input,@"-?\d+(\.\d+)?");
fuente
Podrías usar un código como este:
if (n is IConvertible) return ((IConvertible) n).ToDouble(CultureInfo.CurrentCulture); else // Cannot be converted.
Si el objeto es una
Int32
,Single
,Double
etc. Se llevará a cabo la conversión. Además, se implementa una cadena,IConvertible
pero si la cadena no se puede convertir en un doble, seFormatException
lanzará a.fuente
Si tu requerimiento es realmente
y desea usar double.TryParse, entonces debe usar la sobrecarga que toma un parámetro NumberStyles y asegurarse de que está usando la cultura invariante.
Por ejemplo, para un número que puede tener un signo inicial, sin espacios en blanco iniciales o finales, sin separador de miles y un separador decimal de punto, utilice:
NumberStyles style = NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | double.TryParse(input, style, CultureInfo.InvariantCulture, out result);
fuente
Mientras escribía mi propio
object.IsNumeric()
método de extensión basado en la respuesta de Saul Dolgin a esta pregunta, me encontré con un problema potencial en el que obtendrá unOverflowException
si lo intenta condouble.MaxValue
odouble.MinValue
.Mi "solución" fue combinar la respuesta aceptada de Noldorin con la de Saul Dolgin y agregar un interruptor de coincidencia de patrones antes de intentar analizar cualquier cosa (y usar algo de bondad de C # 7 para ordenar un poco):
public static bool IsNumeric(this object obj) { if (obj == null) return false; switch (obj) { case sbyte _: return true; case byte _: return true; case short _: return true; case ushort _: return true; case int _: return true; case uint _: return true; case long _: return true; case ulong _: return true; case float _: return true; case double _: return true; case decimal _: return true; } string s = Convert.ToString(obj, CultureInfo.InvariantCulture); return double.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out double _); }
fuente
Si, esto funciona:
object x = 1; Assert.That(x is int);
Para un número de punto flotante, tendría que probar usando el tipo flotante:
object x = 1f; Assert.That(x is float);
fuente