C# - 如何确定Type是否为数字

时间:2009-11-17 16:15:05

标签: c# .net types

有没有办法确定给定的.Net Type是否为数字?例如:System.UInt32/UInt16/Double都是数字。我想避免Type.FullName上的长切换案例。

20 个答案:

答案 0 :(得分:93)

试试这个:

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

基元类型是布尔值,字节,   SByte,Int16,UInt16,Int32,UInt32,   Int64,UInt64,Char,Double和   单。   

进一步Guillaume's solution

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

答案 1 :(得分:80)

不要使用开关 - 只需使用一套:

HashSet<Type> NumericTypes = new HashSet<Type>
{
    typeof(decimal), typeof(byte), typeof(sbyte),
    typeof(short), typeof(ushort), ...
};
编辑:使用类型代码的一个优点是,当新的数字类型被引入.NET时(例如BigIntegerComplex),它很容易调整 - 而那些类型不会获取类型代码。

答案 2 :(得分:60)

没有一个解决方案考虑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?),
        ...
    };

答案 3 :(得分:35)

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

关于删除优化的注意事项(请参阅enzi注释) <击> 如果你真的想要优化它(失去可读性和安全性......):

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

<击>

答案 4 :(得分:12)

基本上是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);
    }
}

答案 5 :(得分:9)

基于Philip's proposal的方法,针对Nullable类型的SFun28's inner type check进行了增强:

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是否为数字。

答案 6 :(得分:3)

使用C#7,这种方法比basePathTypeCode上的切换案例给出了更好的性能:

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;

答案 7 :(得分:1)

您可以使用Type.IsPrimitive然后整理BooleanChar类型,如下所示:

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

编辑:如果您不认为它们是数字,您可能还想排除IntPtrUIntPtr类型。

答案 8 :(得分:1)

简短回答:不。

更长的答案:没有。

事实上,C#中的许多不同类型都可以包含数字数据。除非你知道会发生什么(Int,Double等),否则你需要使用“long”case语句。

答案 9 :(得分:1)

bool IsNumeric(Type type)
    => type == typeof(decimal)
    || type == typeof(int) 
    || type == typeof(uint)
    || type == typeof(long)
    || type == typeof(ulong)
    || type == typeof(short)
    || type == typeof(ushort)
    || type == typeof(byte)
    || type == typeof(sbyte)
    || type == typeof(float)
    || type == typeof(double)
    ;

答案 10 :(得分:1)

这可能也有效。但是,您可能希望使用Type.Parse进行跟踪,然后按照您希望的方式进行投射。

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

答案 11 :(得分:1)

具有空类型支持的类型扩展。

public static bool IsNumeric(this Type type)
    {
        if (type == null) { return false; }

        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            type = type.GetGenericArguments()[0];
        }

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

答案 12 :(得分:0)

只是添加到查看 TypeCode 的其他答案中 - 如果您愿意,您可以进一步简化,以避免冗长的 switch 语句:

    public static bool IsNumeric(this Type type)
    {
        var typeCode = (int)Type.GetTypeCode(type);
        return typeCode > 4 && typeCode < 16;
    }

    public static bool IsNumeric(this object source)
    {
        return source.GetType().IsNumeric();
    }

答案 13 :(得分:0)

尝试使用C#的TypeSupport nuget软件包。它支持检测所有数字类型(还有许多其他功能):

var extendedType = typeof(int).GetExtendedType();
Assert.IsTrue(extendedType.IsNumericType);

答案 14 :(得分:0)

开关有点慢,因为每次在最坏情况下的方法都会经过所有类型。 我认为,使用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);
    }
}

答案 15 :(得分:0)

编辑:好吧,我修改了以下代码,使其性能更高,然后针对它运行了@Hugo发布的测试。使用他序列中的最后一项(十进制),速度与@Hugo的IF差不多。但是,如果使用第一项“字节”,那么他就吃了蛋糕,但显然在性能方面顺序很重要。尽管使用下面的代码更容易编写并且在成本上更一致,但是,它不可维护或无法证明未来。

就像从Type.GetTypeCode()转换为Convert.GetTypeCode()一样,性能大幅提高了25%,而VS Enum.Parse()却慢了10倍。


我知道这篇文章很老,但是 IF 使用TypeCode枚举方法,最简单(可能也是最便宜)的是这样的:

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的其他类型进行更新。

答案 16 :(得分:0)

使用GenericsReflectionC# v6.0修改了双向飞碟和arviman的解决方案。

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。

答案 17 :(得分:0)

它们都是值类型(bool和enum除外)。所以你可以简单地使用:

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

答案 18 :(得分:0)

不幸的是,除了它们都是值类型之外,这些类型没有太多共同之处。但是为了避免长切换情况,您可以只定义包含所有这些类型的只读列表,然后检查给定类型是否在列表中。

答案 19 :(得分:-1)

糟糕!误读了这个问题!就个人而言,会与Skeet's滚动。


hrm,听起来好像是DoSomething数据的Type。您可以做的是以下

public class MyClass
{
    private readonly Dictionary<Type, Func<SomeResult, object>> _map = 
        new Dictionary<Type, Func<SomeResult, object>> ();

    public MyClass ()
    {
        _map.Add (typeof (int), o => return SomeTypeSafeMethod ((int)(o)));
    }

    public SomeResult DoSomething<T>(T numericValue)
    {
        Type valueType = typeof (T);
        if (!_map.Contains (valueType))
        {
            throw new NotSupportedException (
                string.Format (
                "Does not support Type [{0}].", valueType.Name));
        }
        SomeResult result = _map[valueType] (numericValue);
        return result;
    }
}