检查对象是否为C#中的数字


89

我想检查的对象是一个数字,这样.ToString()会导致包含数字和字符串+-.

是否可以通过.net中的简单类型检查(例如:)进行操作if (p is Number)

还是应该转换为字符串,然后尝试将其解析为两倍?

更新:澄清我的对象是int,uint,float,double,等等,它不是字符串。我正在尝试制作一个将任何对象序列化为xml的函数,如下所示:

<string>content</string>

要么

<numeric>123.3</numeric>

或提出例外。


5
像你这样的声音正在尝试写自己的XmlSerializer-什么是错与.NET-的一个供应商msdn.microsoft.com/en-us/library/...
RichardOD

2
通过使用XSD定义XML格式,然后创建一个可以使用附带的XSD工具将数据序列化到其中的对象,您也许可以解决整个问题-msdn.microsoft.com/zh-cn/library/x6c1kb0s %28VS.71%29.aspx
Dexter,2009年

@RichardOD:我可以使用xml序列化来序列化object []吗?我需要它来调用闪光功能adobe.com/livedocs/flex/201/html/wwhelp/wwhimpl/common/html/...
彼得·Czapla

Answers:


180

您只需要对每种基本数字类型进行类型检查。

这是应该做的扩展方法:

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/ 添加其他调用即可。


我的对象是int,short,uint,float,double或其他任何数字
Piotr Czapla

@Piotr:好的。看来我误会了你。看到我更新的答案。
Noldorin

1
@Noldorin:实际上,您以前的代码版本同样适用;只需添加一个空检查并使用value.ToString()。然后,您无需检查所有数字类型。
FredrikMörk,2009年

1
@Noldorin可悲的是,它的正确的解决方案是冗长:(。
彼得·Czapla

1
@Joe:实际上,这没有什么区别,因为ToString也将使用当前的区域性。
Noldorin

36

摘自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
这种方法的问题是,如果您传递一个看起来像数字的字符串,它将对其进行格式化。对于大多数人来说可能还可以,但对我来说,这是一个表演的障碍。
Rob Sedgwick 2015年

1
另一个潜在的问题是,您无法解析double的最小值/最大值。double.Parse(double.MaxValue.ToString())导致OverflowException。您可以.ToString("R")在这种情况下通过提供来回修饰符来解决此问题,但是Convert.ToString(...)由于我们不知道类型,所以该重载不可用。我知道这是一个小问题,但是我在为自己的.IsNumeric()扩展编写测试时偶然发现了它。我的“解决方案”是在尝试解析任何内容之前添加一个类型检查swtich的代码,请参见我对此问题的回答。

21

利用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()框值类型,因此删除了泛型。还包括对可为空值的修复。


1
泛型部分在这里没有给您任何额外收益,是吗?您只能访问对象上可用的GetType()...
Peter Lillevold 09年

如果在值类型上调用它,则可以保存一个框操作。考虑可重用性。
Kenan EK,2009年

1
为什么不使用typeof(T)而不是obj.GetType,那样的话,如果有人传递空引用类型,您将不会收到NullReferenceException。您还可以在T上设置通用约束,使其仅接受值类型。当然,如果您这样做的话,您会在编译时开始拥有很多信息。
Trillian

object并且string不是原始类型。
我们都是莫妮卡

@jnylen:这个答案是相当早以前的。我相信我当时从反射框架的源头挖了一些东西,但是谁能告诉今天...固定答案。
Kenan EK

10

上面有一些很好的答案。这是一个多合一的解决方案。针对不同情况的三个重载。

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

考虑添加空检查
wiero

确实不需要null检查-作为扩展方法,您不能使用null值来调用它。当然,仍然有人可以调用它作为普通函数,但这不是扩展方法的预期用法。
米克·布鲁诺

5
我认为可以用空值来称呼它。对象obj = null; obj.IsNumeric();
wiero

感谢Weiro,已解决问题。没想到可以用空值调用扩展方法,但是当然可以!
米克·布鲁诺

我认为第一个重载末尾缺少括号:“ return(x == null?false:IsNumeric(x.GetType()));”
glenn garson 2014年

8

判断内置类型是否为数字的最可靠方法不是滚动自己的方法,而是引用Microsoft.VisualBasic和调用Information.IsNumeric(object value)。该实现处理许多微妙的情况,例如char[]HEX和OCT字符串。


这应该在顶部!
nawfal

4

那里有三个不同的概念:

  • 要检查它是否是数字(即本身(通常是装箱的)数字值),请使用is- 检查类型if(obj is int) {...}
  • 检查字符串是否可以解析为数字;用TryParse()
  • 但是如果对象不是数字或字符串,但是您怀疑ToString()可能给出的东西看起来像数字,请调用 ToString()并将其视为字符串

在前两种情况下,您可能必须分别处理要支持的每种数字类型(double/ decimal/int)-例如,都具有不同的范围和精度。

您也可以查看regex进行快速粗略检查。


4

假设您输入的是字符串...

有两种方法:

使用Double.TryParse()

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

使用正则表达式

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

3

您可以使用如下代码:

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

如果你的对象是Int32SingleDouble等它执行转换。同样,字符串实现了,IConvertible但是如果字符串不能转换为双精度数,FormatException则将抛出a。


实际上将解析字符串,但是如果格式不正确,则会引发FormatException。
alfoks 18-10-16

@alfoks:您绝对正确,所以我更新了答案。
Martin Liversage,

1

如果您的要求确实是

.ToString()将导致包含数字和+,-,的字符串。

并且要使用double.TryParse,则需要使用带有NumberStyles参数的重载,并确保使用的是不变式区域性。

例如,对于可能具有前导符号,没有前导或尾随空格,没有千位分隔符和句点小数点分隔符的数字,请使用:

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

1

object.IsNumeric()根据Saul Dolgin对这个问题的回答编写自己的扩展方法时,我遇到了一个潜在的问题,OverflowException如果使用double.MaxValue或尝试将得到一个double.MinValue

我的“解决方案”是将Noldorin接受的答案与Saul Dolgin的答案相结合,并在尝试解析任何内容之前添加模式匹配开关(并使用C#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 _);
}

0

是的,这可行:

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

对于浮点数,您必须使用浮点类型进行测试:

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

如果在将对象隐式或显式转换为对象之前是int类型,这将起作用。在您的示例中,魔术数字1是一个int,然后被隐式转换为变量x的类型。如果完成对象x = 1.0,则断言将返回false。
德克斯特(Dexter)2009年

有些数字不是整数。
FredrikMörk,2009年

是的,所以我的意思基本上是@Noldorin现在在回答中说的话。
Peter Lillevold 09年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.