Je voudrais vérifier si un objet est un nombre pour que .ToString()
donne une chaîne contenant des chiffres et +
, -
, .
Est-il possible par simple vérification de type dans .net (comme: if (p is Number)
)?
Ou devrais-je convertir en chaîne, puis essayer de doubler?
pdate: Pour clarifier mon objet, c'est int, uint, float, double, etc., ce n'est pas une chaîne. J'essaie de créer une fonction qui sérialiserait n'importe quel objet en XML comme ceci:
<string>content</string>
ou
<numeric>123.3</numeric>
ou lever une exception.
Vous aurez simplement besoin de faire une vérification de type pour chacun des types numériques de base.
Voici une méthode d'extension qui devrait faire le travail:
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;
}
Cela devrait couvrir tous les types numériques.
Il semble que vous souhaitiez réellement analyser le numéro d'une chaîne lors de la désérialisation. Dans ce cas, il vaudrait probablement mieux utiliser double.TryParse
.
string value = "123.3";
double num;
if (!double.TryParse(value, out num))
throw new InvalidOperationException("Value is not a number.");
Bien sûr, cela ne traiterait pas les entiers très grands/décimales longs, mais si c'est le cas, il vous suffit d'ajouter des appels supplémentaires à long.TryParse
/decimal.TryParse
/n'importe quoi d'autre.
Tiré de 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);
}
Tirez parti de la propriété IsPrimitive pour créer une méthode d’extension pratique:
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);
}
EDIT: Fixé selon les commentaires. Les génériques ont été supprimés car les types de valeur des boîtes .GetType (). Également inclus correctif pour les valeurs nullables.
Il y a quelques bonnes réponses ci-dessus. Voici une solution tout-en-un. Trois surcharges pour des circonstances différentes.
// 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)); }
Plutôt que de lancer le vôtre, le moyen le plus fiable de déterminer si un type intégré est numérique est probablement de faire référence à Microsoft.VisualBasic
Et d'appeler Information.IsNumeric(object value)
. L'implémentation gère un certain nombre de cas subtils tels que les chaînes char[]
Et HEX et OCT.
Il y a trois concepts différents:
is
- par exemple if(obj is int) {...}
TryParse()
ToString()
peut donner quelque chose qui ressemble à un nombre, then callToString()
et le traite comme une chaîneDans les deux premiers cas, vous devrez probablement gérer séparément chaque type numérique que vous souhaitez prendre en charge (double
/decimal
/int
) - chacun ayant des plages différentes et la précision, par exemple.
Vous pouvez également consulter regex pour une vérification rapide.
En supposant que votre entrée est une chaîne ...
Il y a 2 façons:
utilisez Double.TryParse ()
double temp;
bool isNumber = Double.TryParse(input, out temp);
utiliser Regex
bool isNumber = Regex.IsMatch(input,@"-?\d+(\.\d+)?");
Vous pouvez utiliser un code comme ceci:
if (n is IConvertible)
return ((IConvertible) n).ToDouble(CultureInfo.CurrentCulture);
else
// Cannot be converted.
Si votre objet est un Int32
, Single
, Double
etc., il effectuera la conversion. De plus, une chaîne implémente IConvertible
mais si la chaîne n'est pas convertible en double, un FormatException
sera lancé.
Si votre exigence est vraiment
.ToString () donnerait une chaîne contenant des chiffres et +, - ,.
si vous voulez utiliser double.TryParse, vous devez utiliser la surcharge qui prend un paramètre NumberStyles et vous assurer que vous utilisez la culture invariante.
Par exemple, pour un nombre qui peut avoir un signe de tête, aucun espace de début ou de fin, aucun séparateur de milliers et un séparateur décimal de période, utilisez:
NumberStyles style =
NumberStyles.AllowLeadingSign |
NumberStyles.AllowDecimalPoint |
double.TryParse(input, style, CultureInfo.InvariantCulture, out result);
Lors de l'écriture de ma propre méthode d'extension object.IsNumeric()
basée sur la réponse de Saul Dolgin à cette question, j'ai rencontré un problème potentiel dans lequel vous obtiendrez un OverflowException
si vous l'essayez avec double.MaxValue
ou double.MinValue
.
Ma "solution" consistait à combiner la réponse acceptée de Noldorin à celle de Saul Dolgin et à ajouter un commutateur de correspondance de motif avant d'essayer d'analyser quoi que ce soit (et d'utiliser un peu de bonté C # 7 pour ranger un peu):
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 _);
}
Oui, cela fonctionne:
object x = 1;
Assert.That(x is int);
Pour un nombre à virgule flottante, vous devrez tester en utilisant le type float:
object x = 1f;
Assert.That(x is float);