C# – 如何确定一个types是一个数字

有没有办法确定一个给定的.Nettypes是否是一个数字? 例如: System.UInt32/UInt16/Double都是数字。 我想避免Type.FullName上的一个长开关的情况。

尝试这个:

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

原始types是布尔,Byte,SByte,Int16,UInt16,Int32,UInt32,Int64,UInt64,Char,Double和Single。

让Guillaume的解决scheme更进一步:

 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 

不要使用开关 – 只需使用一组:

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

编辑:使用types代码的一个优点是,当新的数字types被引入.NET(如BigInteger和复杂 )很容易调整 – 而这些types不会得到一个types的代码。

这些解决scheme都不考虑Nullable。

我修改了Jon Skeet的解决scheme:

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

我知道我可以添加空的本身到我的HashSet。 但是这个解决scheme避免了忘记添加一个特定的Nullable到你的列表的危险。

  private static HashSet<Type> NumericTypes = new HashSet<Type> { typeof(int), typeof(int?), ... }; 
 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; } 

方法基于Philip的build议 ,增加了SFun28的内部types检查 Nullabletypes:

 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是否是一个数字types,而不是一个任意的object o是否是数字types。

基本上Skeet的解决scheme,但你可以重复使用Nullabletypes如下:

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

您可以使用Type.IsPrimitive ,然后梳理BooleanChartypes,如下所示:

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

编辑 :你可能想要排除IntPtrUIntPtrtypes以及,如果你不认为他们是数字。

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

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

不幸的是,这些types除了它们都是值types之外没有太多共同之处。 但是为了避免长时间的切换,你可以定义一个只读列表,然后检查给定types是否在列表中。

简短的回答:不。

更长的答案:不。

事实是,C#中的许多不同types可以包含数字数据。 除非你知道期望什么(Int,Double等),否则你需要使用“long”case语句。

哎呀! 错误的问题! 就个人而言,会与Skeet的 。


人力资源pipe理,听起来像你想在你的数据TypeDoSomething 。 你可以做的是以下

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

这也可以工作。 但是,您可能想要使用Type.Parse来追踪它,然后按照您希望的方式进行投射。

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

使用GenericsReflectionC# v6.0修改飞碟和arviman的解决scheme。

 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。

使用C#7,这种方法比TypeCodeHashSet<Type>上的switch case更能提供更好的性能:

 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; 

testing如下:

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