Подтвердить что ты не робот

Проверка того, является ли объект числом в С#

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

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

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

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

<string>content</string>

или

<numeric>123.3</numeric>

или создать исключение.

4b9b3361

Ответ 1

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

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

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

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

Update

Кажется, вы действительно хотите разбирать номер из строки во время десериализации. В этом случае, вероятно, лучше всего использовать 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/whatever else.

Ответ 2

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

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

Ответ 3

Воспользуйтесь свойством 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);
}

EDIT: исправлено в соответствии с комментариями. Дженерики были удалены, так как типы значений .GetType() присваивают значения. Также включено исправление для значений с нулевым значением.

Ответ 4

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

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

Ответ 5

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

Ответ 6

Существует три разных понятия:

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

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

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

Ответ 7

Предполагая, что ваш ввод является строкой...

Есть два способа:

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

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

использовать Regex

 bool isNumber = Regex.IsMatch(input,@"-?\d+(\.\d+)?");

Ответ 8

Вы можете использовать такой код:

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

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

Ответ 9

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

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

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

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

Ответ 10

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

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

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

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

NumberStyles style = 
   NumberStyles.AllowLeadingSign | 
   NumberStyles.AllowDecimalPoint | 
double.TryParse(input, style, CultureInfo.InvariantCulture, out result);

Ответ 11

При написании собственного object.IsNumeric() расширения object.IsNumeric() основанного на ответе Сола Долгина на этот вопрос, я столкнулся с потенциальной проблемой, double.MaxValue в том, что вы получите OverflowException если попробуете это с double.MaxValue или double.MinValue.

Моим "решением" было объединить принятый ответ от Noldorin с ответом от Saul Dolgin и добавить переключатель сопоставления с образцом, прежде чем пытаться что-то анализировать (и использовать некоторую доброту С# 7, чтобы немного привести в порядок):

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