在 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.
如果您的对象是Int32
、Single
、Double
等,它将执行转换。此外,字符串实现了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 施加通用约束以仅接受值类型。当然,如果你这样做,你会在编译时开始获得大量信息。object
和 string
不是原始类型。
@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.MaxValue
或 double.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# 中检查对象是不是为数字的主要内容,如果未能解决你的问题,请参考以下文章