web-dev-qa-db-ja.com

C#-タイプが数値かどうかを判断する方法

特定の.Netタイプが数値であるかどうかを判断する方法はありますか?例:System.UInt32/UInt16/Doubleはすべて数字です。 Type.FullNameの長いスイッチケースを避けたい。

89
Adi Barda

これを試して:

Type type = object.GetType();
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));

プリミティブ型は、ブール、バイト、Sバイト、Int16、UInt16、Int32、UInt32、Int64、UInt64、Char、Double、およびSingleです。

ギヨームの解 をもう少し取って:

public static bool IsNumericType(this object o)
{   
  switch (Type.GetTypeCode(o.GetType()))
  {
    case TypeCode.Byte:
    case TypeCode.SByte:
    case TypeCode.UInt16:
    case TypeCode.UInt32:
    case TypeCode.UInt64:
    case TypeCode.Int16:
    case TypeCode.Int32:
    case TypeCode.Int64:
    case TypeCode.Decimal:
    case TypeCode.Double:
    case TypeCode.Single:
      return true;
    default:
      return false;
  }
}

使用法:

int i = 32;
i.IsNumericType(); // True

string s = "Hello World";
s.IsNumericType(); // False
95
Philip Wallace

スイッチを使用しないでください-セットを使用するだけです:

HashSet<Type> NumericTypes = new HashSet<Type>
{
    typeof(decimal), typeof(byte), typeof(sbyte),
    typeof(short), typeof(ushort), ...
};

編集:型コードを使用するよりもこの利点の1つは、新しい数値型が.NETに導入されたときに(たとえば BigInteger および Complex )調整しやすいことです-これらの型は、タイプコードを取得しません

83
Jon Skeet

Nullableを考慮に入れるソリューションはありません。

Jon Skeetのソリューションを少し変更しました。

    private static HashSet<Type> NumericTypes = new HashSet<Type>
    {
        typeof(int),
        typeof(uint),
        typeof(double),
        typeof(decimal),
        ...
    };

    internal static bool IsNumericType(Type type)
    {
        return NumericTypes.Contains(type) ||
               NumericTypes.Contains(Nullable.GetUnderlyingType(type));
    }

Nullables自体をHashSetに追加できることはわかっています。しかし、このソリューションは、リストに特定のNullableを追加することを忘れる危険を回避します。

    private static HashSet<Type> NumericTypes = new HashSet<Type>
    {
        typeof(int),
        typeof(int?),
        ...
    };
64
public static bool IsNumericType(Type type)
{
  switch (Type.GetTypeCode(type))
  {
    case TypeCode.Byte:
    case TypeCode.SByte:
    case TypeCode.UInt16:
    case TypeCode.UInt32:
    case TypeCode.UInt64:
    case TypeCode.Int16:
    case TypeCode.Int32:
    case TypeCode.Int64:
    case TypeCode.Decimal:
    case TypeCode.Double:
    case TypeCode.Single:
      return true;
    default:
      return false;
  }
}

最適化に関する注意を削除(エンジコメントを参照) そして、あなたが本当にそれを最適化したいなら(読みやすさといくつかの安全性を失います...):

public static bool IsNumericType(Type type)
{
  TypeCode typeCode = Type.GetTypeCode(type);
  //The TypeCode of numerical types are between SByte (5) and Decimal (15).
  return (int)typeCode >= 5 && (int)typeCode <= 15;
}
35
Guillaume

基本的にSkeetのソリューションですが、次のようにNullable型で再利用できます。

public static class TypeHelper
{
    private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
    {
        typeof(int),  typeof(double),  typeof(decimal),
        typeof(long), typeof(short),   typeof(sbyte),
        typeof(byte), typeof(ulong),   typeof(ushort),  
        typeof(uint), typeof(float)
    };

    public static bool IsNumeric(Type myType)
    {
       return NumericTypes.Contains(Nullable.GetUnderlyingType(myType) ?? myType);
    }
}
14
arviman

Philipの提案 に基づくアプローチ、 SFun28の内部型チェック で強化され、Nullable型に対して:

public static class IsNumericType
{
    public static bool IsNumeric(this Type type)
    {
        switch (Type.GetTypeCode(type))
        {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Single:
                return true;
            case TypeCode.Object:
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    return Nullable.GetUnderlyingType(type).IsNumeric();
                    //return IsNumeric(Nullable.GetUnderlyingType(type));
                }
                return false;
            default:
                return false;
        }
    }
}

なんでこれ?特定のType typeは数値型であり、任意のobject oは数値です。

9
cimnine

C#7では、このメソッドはTypeCodeおよびHashSet<Type>

public static bool IsNumeric(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is float || o is double || o is decimal;

テストは次のとおりです。

public static class Extensions
{
    public static HashSet<Type> NumericTypes = new HashSet<Type>()
    {
        typeof(byte), typeof(sbyte), typeof(ushort), typeof(uint), typeof(ulong), typeof(short), typeof(int), typeof(long), typeof(decimal), typeof(double), typeof(float)
    };

    public static bool IsNumeric1(this object o) => NumericTypes.Contains(o.GetType());

    public static bool IsNumeric2(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is decimal || o is double || o is float;

    public static bool IsNumeric3(this object o)
    {
        switch (o)
        {
            case Byte b:
            case SByte sb:
            case UInt16 u16:
            case UInt32 u32:
            case UInt64 u64:
            case Int16 i16:
            case Int32 i32:
            case Int64 i64:
            case Decimal m:
            case Double d:
            case Single f:
                return true;
            default:
                return false;
        }
    }

    public static bool IsNumeric4(this object o)
    {
        switch (Type.GetTypeCode(o.GetType()))
        {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Single:
                return true;
            default:
                return false;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {           
        var count = 100000000;

        //warm up calls
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric1();
        }
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric2();
        }
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric3();
        }
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric4();
        }

        //Tests begin here
        var sw = new Stopwatch();
        sw.Restart();
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric1();
        }
        sw.Stop();

        Debug.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric2();
        }
        sw.Stop();

        Debug.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric3();
        }
        sw.Stop();

        Debug.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric4();
        }
        sw.Stop();

        Debug.WriteLine(sw.ElapsedMilliseconds);
    }
3
Hugo Freitas

Type.IsPrimitive を使用して、BooleanおよびCharタイプを次のように整理できます。

bool IsNumeric(Type type)
{
    return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool);
}

[〜#〜] edit [〜#〜]IntPtrおよびUIntPtrタイプを除外することができます。同様に、数値とみなさない場合。

2
Konamiman

短い答え:いいえ。

長い回答:いいえ。

実際、C#の多くの異なる型には数値データを含めることができます。予想される内容(Int、Doubleなど)がわからない場合は、「長い」caseステートメントを使用する必要があります。

1
Craig

これもうまくいくかもしれません。ただし、Type.Parseでフォローアップして、後で望むようにキャストすることができます。

public bool IsNumeric(object value)
{
    float testValue;
    return float.TryParse(value.ToString(), out testValue);
}
1
DaveT

編集:さて、私は以下のコードをより高性能に変更し、それに対して@Hugoによって投稿されたテストを実行しました。速度は、シーケンスの最後の項目(10進数)を使用した@HugoのIFとほぼ同等です。しかし、最初のアイテム「バイト」を使用する場合、彼はケーキを取りますが、パフォーマンスに関しては明らかに順序が重要です。以下のコードを使用すると、作成が容易になり、コストの一貫性が高まりますが、保守や将来の証明ができません。

Type.GetTypeCode()からConvert.GetTypeCode()に切り替えると、パフォーマンスが大幅に向上し、約25%、VS Enum.Parse()が10倍遅くなったように見えます。


私はこの投稿が古いことを知っていますが、[〜#〜] if [〜#〜] TypeCode enumメソッドを使用すると、最も簡単な(そしておそらく最も安い)は次のようになります。

public static bool IsNumericType(this object o)
{   
  var t = (byte)Convert.GetTypeCode(o);
  return t > 4 && t < 16;
}

TypeCodeに次の列挙型定義がある場合:

public enum TypeCode
{
    Empty = 0,
    Object = 1,
    DBNull = 2,
    Boolean = 3,
    Char = 4,
    SByte = 5,
    Byte = 6,
    Int16 = 7,
    UInt16 = 8,
    Int32 = 9,
    UInt32 = 10,
    Int64 = 11,
    UInt64 = 12,
    Single = 13,
    Double = 14,
    Decimal = 15,
    DateTime = 16,
    String = 18
}

私はそれを徹底的にテストしていませんが、基本的なC#数値型の場合、これで対応できるようです。ただし、@ JonSkeetが述べたように、この列挙型は、将来的に.NETに追加された追加の型に対しては更新されません。

0
Hector Bas

これらはすべて値型です(boolおよび多分enumを除く)。だからあなたは単に使用することができます:

bool IsNumberic(object o)
{
    return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum))
}
0
MandoMando

GenericsReflection、およびC# v6.0を使用する修正されたスキートおよびアルビマンのソリューション。

private static readonly HashSet<Type> m_numTypes = new HashSet<Type>
{
    typeof(int),  typeof(double),  typeof(decimal),
    typeof(long), typeof(short),   typeof(sbyte),
    typeof(byte), typeof(ulong),   typeof(ushort),
    typeof(uint), typeof(float),   typeof(BigInteger)
};

に続く:

public static bool IsNumeric<T>( this T myType )
{
    var IsNumeric = false;

    if( myType != null )
    {
        IsNumeric = m_numTypes.Contains( myType.GetType() );
    }

    return IsNumeric;
}

(T item)の使用法:

if ( item.IsNumeric() ) {}

nullはfalseを返します。

0
HouseCat

切り替えは少し遅いですが、最悪の状況での方法がすべてのタイプを通過するたびに原因です。 Dictonaryを使用するほうがいいと思います。この状況ではO(1)になります:

public static class TypeExtensions
{
    private static readonly HashSet<Type> NumberTypes = new HashSet<Type>();

    static TypeExtensions()
    {
        NumberTypes.Add(typeof(byte));
        NumberTypes.Add(typeof(decimal));
        NumberTypes.Add(typeof(double));
        NumberTypes.Add(typeof(float));
        NumberTypes.Add(typeof(int));
        NumberTypes.Add(typeof(long));
        NumberTypes.Add(typeof(sbyte));
        NumberTypes.Add(typeof(short));
        NumberTypes.Add(typeof(uint));
        NumberTypes.Add(typeof(ulong));
        NumberTypes.Add(typeof(ushort));
    }

    public static bool IsNumber(this Type type)
    {
        return NumberTypes.Contains(type);
    }
}
0
Smagin Alexey

残念ながら、これらの型はすべて値型である以外に共通点はあまりありません。ただし、長いスイッチケースを回避するには、これらのすべてのタイプで読み取り専用リストを定義し、指定されたタイプがリスト内にあるかどうかを確認するだけです。

0
Darin Dimitrov