Is there a way to determine whether or not a given .Net Type is a number? For example: System.UInt32/UInt16/Double
are all numbers. I want to avoid a long switc
You could use Type.IsPrimitive and then sort out the Boolean
and Char
types, something like this:
bool IsNumeric(Type type)
{
return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool);
}
EDIT: You may want to exclude the IntPtr
and UIntPtr
types as well, if you don't consider them to be numeric.
Unfortunately these types don't have much in common other than they are all value types. But to avoid a long switch-case you could just define a readonly list with all these types and then just check if the given type is inside the list.
EDIT: Well, I modified the code below to be more performant and then ran the tests posted by @Hugo against it. The speeds are about on par with @Hugo's IF using the last item in his sequence (Decimal). If however using the first item 'byte' his takes the cake, but clearly order matters when it comes to performance. Although using the code below is easier to write and more consistent on it's cost, it is not, however, maintainable or future proof-able.
Looks like switching from Type.GetTypeCode() to Convert.GetTypeCode() sped up performance drastically, about 25%, VS Enum.Parse() which was like 10 times slower.
I know this post is old but IF using the TypeCode enum method, easiest (and probably the cheapest) would be something like this:
public static bool IsNumericType(this object o)
{
var t = (byte)Convert.GetTypeCode(o);
return t > 4 && t < 16;
}
Given the following enum definition for 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
}
I haven't tested it thoroughly, but for basic C# numeric types, this would seem to cover it. However, as @JonSkeet mentioned, this enum isn't updated for additional types added to .NET down the road.
Try this:
Type type = object.GetType();
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));
The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Double,and Single.
Taking Guillaume's solution a little further:
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;
}
}
Usage:
int i = 32;
i.IsNumericType(); // True
string s = "Hello World";
s.IsNumericType(); // False
Try the TypeSupport nuget package for C#. It has support for detecting all numeric types (among many other features):
var extendedType = typeof(int).GetExtendedType();
Assert.IsTrue(extendedType.IsNumericType);
None of the solutions takes Nullable into account.
I modified Jon Skeet's solution a bit:
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));
}
I know I could just add the nullables itself to my HashSet. But this solution avoid the danger of forgetting to add a specific Nullable to your list.
private static HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int),
typeof(int?),
...
};