web-dev-qa-db-ja.com

オブジェクトがC#の数字かどうかを確認する

.ToString()が数字と_+_、_-_、_._を含む文字列になるように、オブジェクトが数値であるかどうかを確認したい

.netでの単純な型チェックによって可能ですか(例:if (p is Number))?

または、文字列に変換してから、二重に解析してみますか?

更新:私のオブジェクトがint、uint、float、doubleなどであることを明確にするために、それは文字列ではありません。私は次のようにオブジェクトをXMLにシリアル化する関数を作成しようとしています:

_<string>content</string>
_

または

_<numeric>123.3</numeric>
_

または例外を発生させます。

81
Piotr Czapla

基本的な数値型ごとに型チェックを行うだけです。

これを行う拡張メソッドは次のとおりです。

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 /その他の呼び出しを追加するだけです。

164
Noldorin

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);
}
36
Saul Dolgin

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()は値の型をボックス化するため、ジェネリックは削除されました。 null許容値の修正も含まれています。

19
Kenan E. K.

上記のいくつかの素晴らしい答えがあります。これがオールインワンソリューションです。さまざまな状況の3つのオーバーロード。

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

独自に作成するのではなく、組み込み型が数値であるかどうかを判断する最も確実な方法は、おそらく_Microsoft.VisualBasic_を参照してInformation.IsNumeric(object value)を呼び出すことです。実装は、_char[]_やHEXおよびOCT文字列などの多くの微妙なケースを処理します。

7
briantyler

そこには3つの異なる概念があります。

  • is数値(つまり(通常はボックス化された)数値そのもの)かどうかを確認するには、isを使用してタイプを確認します。たとえば、if(obj is int) {...}
  • 文字列を数値として解析できるかどうかを確認します。 TryParse()を使用します
  • しかし、オブジェクトが数字でも文字列でもないが、ToString()が数字のようなlooksを与えると思われる場合、それからcallToString()を文字列として扱います

最初の2つの場合の両方で、サポートする各数値型を個別に処理する必要があります(double/decimal/int)-それぞれ異なる範囲を持ち、たとえば、精度。

また、簡単な大まかなチェックのために正規表現を見ることができます。

4
Marc Gravell

入力が文字列であると仮定します...

2つの方法があります。

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を実装しますが、文字列がdoubleに変換できない場合、FormatExceptionがスローされます。

2

あなたの要件が本当に

.ToString()は、数字と+、-、を含む文字列になります。

double.TryParseを使用する場合は、NumberStylesパラメーターを受け取るオーバーロードを使用し、インバリアントカルチャを使用していることを確認する必要があります。

たとえば、先頭に符号があり、先頭または末尾に空白がなく、千単位の区切り記号とピリオドの小数点記号がない数値の場合、次を使用します。

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

この質問に対するSaul Dolginの答えに基づいて独自のobject.IsNumeric()拡張メソッドを作成しているときに、double.MaxValueで試してみるとOverflowExceptionを取得するという潜在的な問題に遭遇しました。 double.MinValue

私の「解決策」は、ノルドリンの受け入れられた答えとサウル・ドルギンの答えを組み合わせ、パターンマッチングスイッチを追加してから、何かを解析することです(そして、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 _);
}
1
Ben

はい、これは動作します:

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

浮動小数点数の場合、float型を使用してテストする必要があります。

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