在 C# 中检查对象是不是为数字

Posted

技术标签:

【中文标题】在 C# 中检查对象是不是为数字【英文标题】:Checking if an object is a number in C#在 C# 中检查对象是否为数字 【发布时间】:2010-11-10 23:16:08 【问题描述】:

我想检查一个对象是否是一个数字,以便.ToString() 会生成一个包含数字和+,-,. 的字符串

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

或者我应该转换为字符串,然后尝试解析为双精度?

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

<string>content</string>

<numeric>123.3</numeric>

或引发异常。

【问题讨论】:

听起来您正在尝试编写自己的 XmlSerializer - .NET 提供的一个提供程序有什么问题- msdn.microsoft.com/en-us/library/… ? 您可以通过使用 XSD 定义 XML 格式,然后创建一个对象,使用随附的 XSD 工具将数据序列化到该对象中来解决整个问题 - msdn.microsoft.com/en-us/library/x6c1kb0s%28VS.71%29.aspx跨度> @RichardOD:我可以使用 xml 序列化来序列化 object[] 吗?我需要它来调用Flash函数adobe.com/livedocs/flex/201/html/wwhelp/wwhimpl/common/html/… 【参考方案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;

这应该涵盖所有数字类型。

更新

您似乎确实想在反序列化期间从字符串中解析数字。在这种情况下,最好使用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:嗯,对。看来我误会了你。请参阅我的更新答案。 @Noldorin:实际上你以前版本的代码也可以工作;只需添加一个空检查并使用 value.ToString()。那么你就不需要检查所有的数字类型了。 @Noldorin 遗憾的是,正确的解决方案是冗长的:(。 @Joe:实际上,这不会有什么不同,因为 ToString 也会使用当前的文化。【参考方案2】:

是的,这行得通:

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

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

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

【讨论】:

如果对象在被隐式或显式转换为对象之前是一个 int,这将起作用。在您的示例中,幻数 1 是一个 int,然后隐式转换为变量 x.. 的类型。如果您完成了 object x = 1.0,您的断言将返回 false。 有些数字不是整数。 是的,所以我的观点基本上就是@Noldorin 现在的回答。【参考方案3】:

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

有两种方式:

使用 Double.TryParse()

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

使用正则表达式

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

【讨论】:

【参考方案4】:

你可以使用这样的代码:

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

如果您的对象是Int32SingleDouble 等,它将执行转换。此外,字符串实现了IConvertible,但如果字符串不能转换为双精度,则会抛出FormatException

【讨论】:

实际上会解析字符串,但如果格式不正确,则会抛出 FormatException。 @alfoks:你说得对,所以我更新了答案。【参考方案5】:

这里有三个不同的概念:

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

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

您还可以查看正则表达式进行快速粗略检查。

【讨论】:

【参考方案6】:

取自Scott Hanselman's Blog:

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

【讨论】:

这种方法的问题是如果你传入一个看起来像数字的字符串,它会格式化它。对大多数人来说可能没问题,但对我来说这是一个表演障碍。 另一个潜在问题是您无法解析双精度的最小/最大值。 double.Parse(double.MaxValue.ToString()) 导致 OverflowException。在这种情况下,您可以通过提供往返修饰符 .ToString("R") 来解决此问题,但该重载不适用于 Convert.ToString(...),因为我们不知道类型。我知道这是一个边缘案例,但我在为自己的 .IsNumeric() 扩展编写测试时偶然发现了它。我的“解决方案”是在尝试解析任何内容之前添加一个类型检查开关,请参阅我对这个问题的回答以获取代码。【参考方案7】:

利用 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);

编辑:根据 cmets 修复。 由于 .GetType() 框值类型,泛型已被删除。还包括可空值的修复。

【讨论】:

泛型部分在这里没有给你任何额外的东西,是吗?您只能访问对象上可用的 GetType()... 如果在值类型上调用,它会保存一个框操作。考虑可重用性。 为什么不使用 typeof(T) 而不是 obj.GetType,这样如果有人传递了 null 引用类型,你就不会得到 NullReferenceException。您还可以对 T 施加通用约束以仅接受值类型。当然,如果你这样做,你会在编译时开始获得大量信息。 objectstring 不是原始类型。 @jnylen:这个答案是很久以前的了。我相信我当时从反射框架源中挖出了一些东西,但是今天谁能说出来......固定答案。【参考方案8】:

如果你的要求是真的

.ToString() 会产生一个字符串 包含数字和 +,-,.

并且你想使用 double.TryParse 那么你需要使用带有 NumberStyles 参数的重载,并确保你使用的是不变的文化。

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

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

【讨论】:

【参考方案9】:

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

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

【讨论】:

考虑添加空检查 真的不需要空值检查——作为一种扩展方法,你不能用空值调用它。当然,仍然有人可以作为普通函数调用,但这不是扩展方法的预期用法。 我认为可以用空值调用它。对象 obj = null; obj.IsNumeric(); 感谢 Weiro,已修复。没有意识到可以使用 null 值调用扩展方法,但当然可以! 我认为第一个重载在末尾缺少一个括号:“return (x==null ? false : IsNumeric(x.GetType()));”【参考方案10】:

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

【讨论】:

这应该在顶部!【参考方案11】:

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

我的“解决方案”是将 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 _);

【讨论】:

当心可空类型。

以上是关于在 C# 中检查对象是不是为数字的主要内容,如果未能解决你的问题,请参考以下文章

如何检查我的 python 对象是不是为数字? [复制]

如何在 Unity C# 中检查对象是不是面向某个方向

如何检查在 C# 的全局类中找到的数组中是不是存在对象

如何在 C# 中快速检查两个数据传输对象是不是具有相同的属性?

C#中如何检查文本框的输入信息是不是为数字?

如何检查 C# 中的动态匿名类型上是不是存在属性?