Есть ли способ определить, является ли данный .Net Type числом? Например: System.UInt32/UInt16/Double
- все числа. Я хочу избежать длинного переключателя на Type.FullName
.
С# - как определить, является ли тип числом
Ответ 1
Попробуйте следующее:
Type type = object.GetType();
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));
Примитивные типы являются булевыми, байт, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Double и Один.Забастовкa >
Взяв решение Guillaume немного дальше:
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
Ответ 2
Не используйте переключатель - просто используйте набор:
HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(decimal), typeof(byte), typeof(sbyte),
typeof(short), typeof(ushort), ...
};
EDIT: одно из преимуществ этого использования с использованием кода типа заключается в том, что когда новые типы данных вводятся в .NET(например, BigInteger и Complex) его легко настроить - в то время как эти типы не получат код типа.
Ответ 3
Ни одно из решений не учитывает 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?),
...
};
Ответ 4
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) <Удаp > И если вы действительно хотите его оптимизировать (потеря удобочитаемости и некоторая безопасность...):
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;
}
Забастовкa >
Ответ 5
В основном решение 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);
}
}
Ответ 6
Подход на основе Предложения Филиппа, расширенный с помощью проверки внутреннего типа 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
является числовым.
Ответ 7
С С# 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);
}
Ответ 8
Вы можете использовать Type.IsPrimitive, а затем отсортировать типы Boolean
и Char
, что-то вроде этого:
bool IsNumeric(Type type)
{
return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool);
}
EDIT. Вы можете также исключить типы IntPtr
и UIntPtr
, если вы не считаете их числовыми.
Ответ 9
Короткий ответ: Нет.
Дольше ответ: Нет.
Дело в том, что много разных типов в С# могут содержать числовые данные. Если вы не знаете, чего ожидать (Int, Double и т.д.), Вам нужно использовать оператор "long" case.
Ответ 10
Это может сработать. Тем не менее, вы можете захотеть следить за ним с помощью Type.Parse, чтобы отдать его так, как вы захотите.
public bool IsNumeric(object value)
{
float testValue;
return float.TryParse(value.ToString(), out testValue);
}
Ответ 11
К сожалению, эти типы не имеют много общего, кроме всех типов значений. Но чтобы избежать длинного случая переключения, вы можете просто определить список только для чтения со всеми этими типами, а затем просто проверить, находится ли данный тип внутри списка.
Ответ 12
Это все типы значений (кроме bool и, возможно, перечисления). Поэтому вы можете просто использовать:
bool IsNumberic(object o)
{
return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum))
}
Ответ 13
Модифицированное решение skeet и arviman с использованием 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.
Ответ 14
РЕДАКТИРОВАТЬ: Ну, я изменил код ниже, чтобы быть более производительным, а затем провел тесты, опубликованные @Hugo против него. Скорости примерно такие же, как у @Hugo IF, если использовать последний элемент в его последовательности (десятичное число). Однако, если использовать первый элемент "байт", он забирает торт, но порядок имеет значение, когда дело доходит до производительности. Хотя использование приведенного ниже кода проще в написании и более согласовано с его стоимостью, оно, тем не менее, не подлежит обслуживанию и не подлежит проверке в будущем.
Похоже, что переключение с Type.GetTypeCode() на Convert.GetTypeCode() резко увеличило производительность, примерно на 25%, VS Enum.Parse(), которая была примерно в 10 раз медленнее.
Я знаю, что этот пост старый, но если использовать метод перечисления 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
}
Я не проверил это полностью, но для базовых числовых типов С# это, кажется, покрывает это. Однако, как упомянул @JonSkeet, это перечисление не обновляется для дополнительных типов, добавляемых в .NET в будущем.
Ответ 15
упс! Не обращай внимания на вопрос! Лично скачал бы с Skeet.
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;
}
}