Checking if an object is a number in C#

前端 未结 11 1565
粉色の甜心
粉色の甜心 2020-11-29 19:35

I\'d like to check if an object is a number so that .ToString() would result in a string containing digits and +,-,.

相关标签:
11条回答
  • 2020-11-29 20:03

    While writing my own object.IsNumeric() extension method based on Saul Dolgin's answer to this question I ran into a potential issue in that you will get an OverflowException if you try it with double.MaxValue or double.MinValue.

    My "solution" was to combine the accepted answer from Noldorin with the one from Saul Dolgin and add a pattern matching switch before trying to parse anything (and use some C#7 goodness to tidy up a bit):

    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 讨论(0)
  • 2020-11-29 20:04

    Rather than rolling your own, the most reliable way to tell if an in-built type is numeric is probably to reference Microsoft.VisualBasic and call Information.IsNumeric(object value). The implementation handles a number of subtle cases such as char[] and HEX and OCT strings.

    0 讨论(0)
  • 2020-11-29 20:07

    Take advantage of the IsPrimitive property to make a handy extension method:

    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: Fixed as per comments. The generics were removed since .GetType() boxes value types. Also included fix for nullable values.

    0 讨论(0)
  • 2020-11-29 20:08

    Yes, this works:

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

    For a floating point number you would have to test using the float type:

    object x = 1f;
    Assert.That(x is float);
    
    0 讨论(0)
  • 2020-11-29 20:12

    Assuming your input is a string...

    There are 2 ways:

    use Double.TryParse()

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

    use Regex

     bool isNumber = Regex.IsMatch(input,@"-?\d+(\.\d+)?");
    
    0 讨论(0)
  • 2020-11-29 20:14

    You will simply need to do a type check for each of the basic numeric types.

    Here's an extension method that should do the job:

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

    This should cover all numeric types.

    Update

    It seems you do actually want to parse the number from a string during deserialisation. In this case, it would probably just be best to use double.TryParse.

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

    Of course, this wouldn't handle very large integers/long decimals, but if that is the case you just need to add additional calls to long.TryParse / decimal.TryParse / whatever else.

    0 讨论(0)
提交回复
热议问题