web-dev-qa-db-fra.com

Vérifier si un objet est un nombre en C #

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.

81
Piotr Czapla

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.

Mise à jour

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.

164
Noldorin

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);
}
36
Saul Dolgin

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.

19
Kenan E. K.

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)); }
9
Mick Bruno

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.

7
briantyler

Il y a trois concepts différents:

  • pour vérifier si est un nombre (c'est-à-dire une valeur numérique elle-même (généralement encadrée)), vérifiez le type avec is - par exemple if(obj is int) {...}
  • vérifier si une chaîne peut être analysée comme un nombre; utiliser TryParse()
  • mais si l'objet n'est pas un nombre ou une chaîne, mais que vous pensez que ToString() peut donner quelque chose qui ressemble à un nombre, then callToString() et le traite comme une chaîne

Dans 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.

4
Marc Gravell

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+)?");
3
Philippe Leybaert

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é.

2
Martin Liversage

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);
1
Joe

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 _);
}
1
Ben

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);
1
Peter Lillevold