96 votes

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

J'aimerais vérifier si un objet est un nombre pour que .ToString() donnerait une chaîne de caractères contenant des chiffres et + , - , .

Est-il possible de procéder à un simple contrôle de type en .net (comme : if (p is Number) ) ?

Ou dois-je convertir en chaîne de caractères, puis essayer d'analyser en double ?

Mise à jour : Pour clarifier, mon objet est un int, uint, float, double, et ainsi de suite, ce n'est pas une chaîne. J'essaie de créer une fonction qui sérialise n'importe quel objet en xml comme ceci :

<string>content</string>

ou

<numeric>123.3</numeric>

ou de lever une exception.

5 votes

On dirait que vous essayez d'écrire votre propre XmlSerializer - quel est le problème avec le fournisseur de .NET ? msdn.microsoft.com/fr/us/library/ ?

2 votes

Vous pouvez peut-être contourner ce problème en définissant votre format XML à l'aide d'un XSD, puis en créant un objet dans lequel vous pouvez sérialiser vos données à l'aide de l'outil XSD fourni. msdn.microsoft.com/fr/us/library/x6c1kb0s%28VS.71%29.aspx

0 votes

@RichardOD : Puis-je utiliser la sérialisation xml pour sérialiser les objets[] ? J'en ai besoin pour appeler la fonction Flash adobe.com/livedocs/flex/201/html/wwhelp/wwhimpl/common/html/

191voto

Noldorin Points 67794

Vous devrez simplement effectuer un contrôle de type pour chacun des types numériques de base.

Voici une méthode d'extension qui devrait faire l'affaire :

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 en fait analyser le numéro d'une chaîne de caractères pendant la désérialisation. Dans ce cas, il serait probablement préférable d'utiliser la fonction 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 permettrait pas de gérer de très grands nombres entiers ou de longues décimales, mais si c'est le cas, il suffit d'ajouter des appels supplémentaires à la fonction long.TryParse / decimal.TryParse / ou tout autre chose.

0 votes

Mon objet est int, short, uint, float, double ou n'importe quoi d'autre qui est un nombre.

0 votes

@Piotr : Ah oui. Il semble que je vous ai mal compris. Voir ma réponse mise à jour.

1 votes

@Noldorin : en fait, votre version précédente du code fonctionnerait également ; ajoutez simplement une vérification de nullité et utilisez value.ToString(). Ainsi, vous n'avez pas besoin de vérifier tous les types numériques.

36voto

Saul Dolgin Points 4128

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

6 votes

Le problème avec cette approche est que si vous passez une chaîne de caractères qui ressemble à un nombre, il la formatera. Cela peut convenir à la plupart des gens, mais pour moi, c'est un obstacle.

1 votes

Un autre problème potentiel avec ceci est que vous ne pouvez pas analyser les valeurs min/max pour le double. double.Parse(double.MaxValue.ToString()) provoque une OverflowException . Vous pourriez remédier à cela en fournissant le modificateur d'aller-retour .ToString("R") dans ce cas, mais cette surcharge n'est pas disponible pour l'option Convert.ToString(...) car nous ne connaissons pas le type. Je sais que c'est un cas un peu marginal, mais je l'ai rencontré par hasard en écrivant des tests pour ma propre application .IsNumeric() extension. Ma "solution" a été d'ajouter un système de vérification de type avant d'essayer d'analyser quoi que ce soit, voir ma réponse à cette question pour le code.

21voto

Kenan E. K. Points 8497

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 : Corrigé selon les commentaires. Les génériques ont été supprimés depuis que .GetType() contient les types de valeurs. Egalement inclus un correctif pour les valeurs nullables.

1 votes

La partie générique ne vous apporte rien de plus ici, n'est-ce pas ? Vous accédez seulement à GetType() qui est disponible sur l'objet...

0 votes

Elle permet d'économiser une opération de boîte si elle est appelée sur un type de valeur. Pensez à la réutilisation.

1 votes

Pourquoi ne pas utiliser typeof(T) au lieu de obj.GetType, de cette façon vous n'obtiendrez pas une NullReferenceException si quelqu'un passe un type de référence nul. Vous pourriez aussi mettre une contrainte générique sur T pour qu'il n'accepte que les types de valeur. Bien sûr, si vous faites cela, vous commencez à avoir beaucoup d'informations au moment de la compilation.

10voto

Mick Bruno Points 184

Il y a d'excellentes réponses ci-dessus. Voici une solution tout-en-un. Trois surcharges pour différentes circonstances.

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

0 votes

Envisager l'ajout d'un contrôle nul

0 votes

N'a pas vraiment besoin de la vérification de nullité - en tant que méthode d'extension, vous ne pourriez pas l'appeler avec une valeur nulle. Bien sûr, quelqu'un pourrait toujours l'appeler comme une fonction normale, mais ce n'est pas l'usage attendu d'une méthode d'extension.

5 votes

Je pense qu'on peut l'appeler avec une valeur nulle. objet obj = null ; obj.IsNumeric() ;

4voto

Marc Gravell Points 482669

Il y a là trois concepts différents :

  • pour vérifier s'il est un nombre (c'est-à-dire une valeur numérique (généralement encadrée) elle-même), vérifiez le type avec is - par exemple if(obj is int) {...}
  • pour vérifier si une chaîne peut être analysée comme un nombre ; utilisez TryParse()
  • mais si l'objet n'est pas un nombre ou une chaîne de caractères, mais que vous suspectez ToString() pourrait donner quelque chose qui regarde comme un numéro, alors appelez ToString() et le traiter comme une chaîne de caractères

Dans les deux premiers cas, vous devrez probablement traiter séparément chaque type numérique que vous souhaitez prendre en charge ( double / decimal / int ) - ont chacun une portée et une précision différentes, par exemple.

Vous pouvez également utiliser une expression rationnelle pour effectuer une vérification rapide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X