Проверка, является ли объект числом в C # - PullRequest
81 голосов
/ 15 июля 2009

Я хотел бы проверить, является ли объект числом, чтобы .ToString() приводил к строке, содержащей цифры и +, -, .

Возможно ли это путем простой проверки типа в .net (например: if (p is Number))?

Или я должен преобразовать в строку, а затем попытаться разобрать в удвоение?

Обновление: Чтобы пояснить, мой объект - это int, uint, float, double, и так далее, это не строка. Я пытаюсь сделать функцию, которая сериализует любой объект в XML, как это:

<string>content</string>

или

<numeric>123.3</numeric>

или поднять исключение.

Ответы [ 11 ]

164 голосов
/ 15 июля 2009

Вам просто нужно будет выполнить проверку типов для каждого из основных числовых типов.

Вот метод расширения, который должен выполнять эту работу:

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

Это должно охватывать все числовые типы.

Обновление

Кажется, вы действительно хотите разобрать номер из строки во время десериализации. В этом случае, вероятно, лучше всего использовать double.TryParse.

string value = "123.3";
double num;
if (!double.TryParse(value, out num))
    throw new InvalidOperationException("Value is not a number.");

Конечно, это не будет обрабатывать очень большие целые числа / длинные десятичные дроби, но если это так, вам просто нужно добавить дополнительные вызовы к long.TryParse / decimal.TryParse / что угодно еще.

36 голосов
/ 15 июля 2009

Взято из Блог Скотта Хансельмана :

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);
}
19 голосов
/ 15 июля 2009

Используйте свойство IsPrimitive для создания удобного метода расширения:

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

РЕДАКТИРОВАТЬ: Исправлено в соответствии с комментариями. Обобщения были удалены, так как .GetType () включает значения типов. Также включено исправление для значений Nullable.

9 голосов
/ 17 сентября 2013

Есть несколько отличных ответов выше. Вот решение «все в одном». Три перегрузки для разных обстоятельств.

// 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)); }
7 голосов
/ 06 марта 2015

Вместо того, чтобы бросать свой собственный, самый надежный способ определить, является ли встроенный тип числовым, - это, вероятно, сослаться на Microsoft.VisualBasic и вызвать Information.IsNumeric(object value). Реализация обрабатывает несколько тонких случаев, таких как char[] и строки HEX и OCT.

4 голосов
/ 15 июля 2009

Есть три различных понятия:

  • чтобы проверить, является ли оно числом (т. Е. Самим числовым значением (обычно в штучной упаковке)), проверьте тип с помощью is - например, if(obj is int) {...}
  • чтобы проверить, может ли строка быть проанализирована как число; используйте TryParse()
  • но если объект не является числом или строкой, но вы подозреваете, что ToString() может дать что-то, что выглядит как число, тогда вызовите ToString() и обработайте это как строка

В обоих первых двух случаях вам, вероятно, придется обрабатывать отдельно каждый числовой тип, который вы хотите поддерживать (double / decimal / int) - например, каждый имеет разные диапазоны и точность.

Вы также можете посмотреть на регулярные выражения для быстрой грубой проверки.

3 голосов
/ 15 июля 2009

Предполагая, что вы вводите строку ...

Есть 2 способа:

используйте Double.TryParse ()

double temp;
bool isNumber = Double.TryParse(input, out temp);

используйте Regex

 bool isNumber = Regex.IsMatch(input,@"-?\d+(\.\d+)?");
2 голосов
/ 15 июля 2009

Вы можете использовать код, подобный этому:

if (n is IConvertible)
  return ((IConvertible) n).ToDouble(CultureInfo.CurrentCulture);
else
  // Cannot be converted.

Если ваш объект - Int32, Single, Double и т. Д., Он выполнит преобразование. Кроме того, строка реализует IConvertible, но если строка не может быть преобразована в двойное число, будет выброшено FormatException.

1 голос
/ 18 июля 2009

Если ваше требование действительно

.ToString () приведет к строке содержащие цифры и +, -,.

и вы хотите использовать double.TryParse, тогда вам нужно использовать перегрузку, которая принимает параметр NumberStyles, и убедитесь, что вы используете инвариантную культуру.

Например, для числа, которое может иметь начальный знак, без начального или конечного пробела, без разделителя тысяч и десятичного разделителя периода, используйте:

NumberStyles style = 
   NumberStyles.AllowLeadingSign | 
   NumberStyles.AllowDecimalPoint | 
double.TryParse(input, style, CultureInfo.InvariantCulture, out result);
1 голос
/ 15 июля 2009

Да, это работает:

object x = 1;
Assert.That(x is int);

Для числа с плавающей запятой вы должны проверить, используя тип с плавающей запятой:

object x = 1f;
Assert.That(x is float);
...