C# - как определить, является ли тип числом
есть ли способ определить, является ли данный тип .Net числом? Например: System.UInt32/UInt16/Double
все цифры. Я хочу избежать длинного переключателя-кейса на Type.FullName
.
14 ответов:
попробуйте это:Type type = object.GetType(); bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));
примитивные типы являются логическими, байт, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Double, and Одиночный.
С решение Гийома чуть дальше:
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), ... };
EDIT: одно из преимуществ этого перед использованием кода типа заключается в том, что при введении новых числовых типов в .NET (например,BigInteger и комплекс) можно легко регулировать, в то время как эти типы не получить код типа.
ни одно из решений не учитывает Nullable.
Я немного изменил решение Джона Скита:
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?), ... };
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; }
в основном решение скита, но вы можете использовать его с нулевыми типами следующим образом:
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); } }
подход, основанный на Филиппа С проверка внутреннего типа 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
- числовой.
вы могли бы использовать тип.IsPrimitive а потом разобраться
Boolean
иChar
типы, что-то вроде этого:bool IsNumeric(Type type) { return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool); }
EDIT: вы можете исключить
IntPtr
иUIntPtr
типы, а также, если вы не считаете их числовыми.
С C# 7 Этот метод дает мне лучшую производительность, чем switch case on
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); }
короткий ответ: Нет.
Более Длинный Ответ: Нет.
дело в том, что многие различные типы В C# могут содержать числовые данные. Если вы не знаете, чего ожидать (Int, Double и т. д.), Вам нужно использовать оператор "long" case.
все они являются типами значений (за исключением bool и, возможно, enum). Так что вы можете просто использовать:
bool IsNumberic(object o) { return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum)) }
Это тоже может сработать. Тем не менее, вы можете следовать за ним с типом.Разбор, чтобы бросить его так, как вы хотите его впоследствии.
public bool IsNumeric(object value) { float testValue; return float.TryParse(value.ToString(), out testValue); }
к сожалению, эти типы не имеют много общего, кроме того, что они все типы значений. Но чтобы избежать длинного случая переключения, вы можете просто определить список только для чтения со всеми этими типами, а затем просто проверить, находится ли данный тип внутри списка.
упс! Неправильно понял вопрос! Лично, скатился бы с тарелкам!--5-->.
hrm, похоже, вы хотите
DoSomething
onType
ваши данные. Что вы могли бы сделать следующее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; } }
модифицированное решение скита и арвимана с использованием
Generics
,Reflection
и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.