Numeric Type Detection in C#

Posted in software by Christopher R. Wirz on Sat Mar 03 2012



C#'s Type object does not have an IsNumeric method or property. Fortunately, it is easy to create an extension method to do this. While there are many approachies using TypeCodes to do this, this will not garuntee support for .Net types.

Note: Double.NaN is supported in all .NET versions 2.0 and greater. double.TryParse(value.ToString()) cannot be assumed to work reliably.

To create an extension method, create a static partial class with static methods. The method body consists of looking within the NumericTypes HashSet for the passed type. An IsNumericType method can be created for an general object using an expression body.


public static partial class TypeExtensions
{
	/// <summary>
	///     The numeric types
	/// </summary>
	public static readonly HashSet<Type> NumericTypes = new HashSet<Type>()
	{
		typeof(byte), typeof(sbyte),
		typeof(int), typeof(uint),
		typeof(UInt16), typeof(UInt32), typeof(UInt64),
		typeof(Int16), typeof(Int32), typeof(Int64),
		typeof(long), typeof(ulong),
		typeof(short), typeof(ushort),
		typeof(float),
		typeof(Single),
		typeof(double),
		typeof(Double),
		typeof(decimal),
		typeof(Decimal),
		// Support for .Net types
		typeof(BigInteger), typeof(Complex)
	};

	/// <summary>
	///     Checks if the type is numeric.
	/// </summary>
	/// <param name="type">The type</param>
	/// <returns>True if the type is numeric</returns>
	public static bool IsNumeric(this Type type)
	{
		// Use the underlying type for nullable numeric types
		while (!NumericTypes.Contains(type) &&
			Type.GetTypeCode(type) == TypeCode.Object &&
			type.IsGenericType &&
			type.GetGenericTypeDefinition() == typeof(Nullable<>))
		{
			type = Nullable.GetUnderlyingType(type);
		}

		return NumericTypes.Contains(type);
	}

	/// <summary>
	///     Determines if an object is of a numeric type.
	/// </summary>
	/// <param name="obj">The object.</param>
	/// <returns>True if the object's type is numeric</returns>
	public static bool IsNumericType(this object obj)
		=> obj != null && obj.GetType().IsNumeric();

}

The above code will require a using statement of the extension methods' namespace to be able to perform the evaluation. To test the result of the evaluation, a series of unit tests may be performed as an example.


[TestClass]
public class TypeExtensionsTests
{
	[TestMethod]
	public void IsNumericBasicTests()
	{
		int a = 1;
		Assert.IsTrue(a.IsNumericType());

		double b = 1.01;
		Assert.IsTrue(b.IsNumericType());

		float c = 1.01F;
		Assert.IsTrue(c.IsNumericType());

		// A string is not a numeric
		string str = "This is a string";
		Assert.IsFalse(str.IsNumericType());
	}

	[TestMethod]
	public void IsNumericTestsForNullableTypes()
	{           
		int? an = 1;
		Assert.IsTrue(an.IsNumericType());

		double? bn = 1.01;
		Assert.IsTrue(bn.IsNumericType());

		float? cn = 1.01F;
		Assert.IsTrue(cn.IsNumericType());
	}

	[TestMethod]
	public void IsNumericTestsForCollections()
	{
		// An array is not a numeric
		int[] aa = new int[] { 1, 98, 2, 97, 3 };
		Assert.IsFalse(aa.IsNumericType());

		// A list is not a numeric
		List<double> dl = new List<double> { 1.2, 98.7, 2.3, 97.8, 3.4 };
		Assert.IsFalse(dl.IsNumericType());

		// use of var should not change the behavior
		var vl = new List<float?> { 1.2F, 98.7F, 2.3F, 97.8F, 3.4F };
		Assert.IsFalse(vl.IsNumericType());
	}
}