Skip to content

Commit

Permalink
Add support for "Half", "Int128", and "UInt128" to numeric extension …
Browse files Browse the repository at this point in the history
…methods
  • Loading branch information
skrysmanski committed Mar 18, 2024
1 parent d5f322e commit 645c5e4
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 113 deletions.
156 changes: 100 additions & 56 deletions src/AppMotor.Core/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,100 +21,144 @@ public static class TypeExtensions
/// and <c>sbyte</c> as well as <see cref="BigInteger"/>. However, <see cref="Complex"/>
/// is excluded.
/// </summary>
/// <remarks>
/// This method checks the type's full name but ignores the type's assembly. It's therefor
/// not 100% foolproof. However, the chance that someone recreates one of the system types
/// which then should not be a numeric value is rather slim (or even impossible?).
/// </remarks>
/// <seealso cref="IsNumericIntegerType"/>
/// <seealso cref="IsNumericFloatType"/>
[MustUseReturnValue]
public static bool IsNumericType(this Type type)
{
Validate.ArgumentWithName(nameof(type)).IsNotNull(type);

switch (type.FullName)
if (type.IsPrimitive)
{
case "System.Byte":
case "System.SByte":
case "System.Int16":
case "System.UInt16":
case "System.Int32":
case "System.UInt32":
case "System.Int64":
case "System.UInt64":
case "System.Numerics.BigInteger":
return true;

case "System.Single":
case "System.Double":
case "System.Decimal":
return true;
switch (type.FullName)
{
case "System.Byte":
case "System.SByte":
case "System.Int16":
case "System.UInt16":
case "System.Int32":
case "System.UInt32":
case "System.Int64":
case "System.UInt64":
return true;

default:
return false;
case "System.Single":
case "System.Double":
return true;

default:
return false;
}
}
else if (type.IsValueType)
{
switch (type.FullName)
{
case "System.Int128":
case "System.UInt128":
case "System.Numerics.BigInteger":
return true;

case "System.Half":
case "System.Decimal":
return true;

default:
return false;
}
}
else
{
return false;
}
}

/// <summary>
/// Returns whether this type is an integer type. This list includes <c>byte</c>
/// and <c>sbyte</c> as well as <see cref="BigInteger"/>.
/// Returns whether this type is an integer type. This list includes <c>byte</c>, <c>sbyte</c>, <see cref="BigInteger"/>,
/// <c>Int128</c>, and <c>UInt128</c>.
/// </summary>
/// <remarks>
/// This method checks the type's full name but ignores the type's assembly. It's therefor
/// not 100% foolproof. However, the chance that someone recreates one of the system types
/// which then should not be a numeric value is rather slim (or even impossible?).
/// </remarks>
/// <seealso cref="IsNumericType"/>
/// <seealso cref="IsNumericFloatType"/>
[MustUseReturnValue]
public static bool IsNumericIntegerType(this Type type)
{
Validate.ArgumentWithName(nameof(type)).IsNotNull(type);

switch (type.FullName)
if (type.IsPrimitive)
{
case "System.Byte":
case "System.SByte":
case "System.Int16":
case "System.UInt16":
case "System.Int32":
case "System.UInt32":
case "System.Int64":
case "System.UInt64":
case "System.Numerics.BigInteger":
return true;
switch (type.FullName)
{
case "System.Byte":
case "System.SByte":
case "System.Int16":
case "System.UInt16":
case "System.Int32":
case "System.UInt32":
case "System.Int64":
case "System.UInt64":
return true;

default:
return false;
default:
return false;
}
}
else if (type.IsValueType)
{
switch (type.FullName)
{
case "System.Int128":
case "System.UInt128":
case "System.Numerics.BigInteger":
return true;

default:
return false;
}
}
else
{
return false;
}
}

/// <summary>
/// Returns whether this type is a floating point type. This list includes <c>float</c>,
/// <c>double</c> and <c>decimal</c>.
/// <c>double</c>, <c>decimal</c>, and <c>Half</c>.
/// </summary>
/// <remarks>
/// This method checks the type's full name but ignores the type's assembly. It's therefor
/// not 100% foolproof. However, the chance that someone recreates one of the system types
/// which then should not be a numeric value is rather slim (or even impossible?).
/// </remarks>
/// <seealso cref="IsNumericIntegerType"/>
/// <seealso cref="IsNumericType"/>
[MustUseReturnValue]
public static bool IsNumericFloatType(this Type type)
{
Validate.ArgumentWithName(nameof(type)).IsNotNull(type);

switch (type.FullName)
if (type.IsPrimitive)
{
case "System.Single":
case "System.Double":
case "System.Decimal":
return true;
switch (type.FullName)
{
case "System.Single":
case "System.Double":
return true;

default:
return false;
default:
return false;
}
}
else if (type.IsValueType)
{
switch (type.FullName)
{
case "System.Half":
case "System.Decimal":
return true;

default:
return false;
}
}
else
{
return false;
}
}

Expand Down
126 changes: 69 additions & 57 deletions tests/AppMotor.Core.Tests/Tests/Extensions/TypeExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,70 +14,82 @@ namespace AppMotor.Core.Tests.Extensions;

public sealed class TypeExtensionsTests
{
[Fact]
public void Test_IsNumericType()
[Theory]
[InlineData(typeof(string), false)]
[InlineData(typeof(char), false)]
[InlineData(typeof(bool), false)]
[InlineData(typeof(IntPtr), false)]
[InlineData(typeof(UIntPtr), false)]
[InlineData(typeof(byte), true)]
[InlineData(typeof(sbyte), true)]
[InlineData(typeof(short), true)]
[InlineData(typeof(ushort), true)]
[InlineData(typeof(int), true)]
[InlineData(typeof(uint), true)]
[InlineData(typeof(long), true)]
[InlineData(typeof(ulong), true)]
[InlineData(typeof(Int128), true)]
[InlineData(typeof(UInt128), true)]
[InlineData(typeof(BigInteger), true)]
[InlineData(typeof(float), true)]
[InlineData(typeof(double), true)]
[InlineData(typeof(Half), true)]
[InlineData(typeof(decimal), true)]
public void Test_IsNumericType(Type type, bool expectedResult)
{
typeof(string).IsNumericType().ShouldBe(false);
typeof(char).IsNumericType().ShouldBe(false);

typeof(byte).IsNumericType().ShouldBe(true);
typeof(sbyte).IsNumericType().ShouldBe(true);
typeof(short).IsNumericType().ShouldBe(true);
typeof(ushort).IsNumericType().ShouldBe(true);
typeof(int).IsNumericType().ShouldBe(true);
typeof(uint).IsNumericType().ShouldBe(true);
typeof(long).IsNumericType().ShouldBe(true);
typeof(ulong).IsNumericType().ShouldBe(true);

typeof(float).IsNumericType().ShouldBe(true);
typeof(double).IsNumericType().ShouldBe(true);
typeof(decimal).IsNumericType().ShouldBe(true);

typeof(BigInteger).IsNumericType().ShouldBe(true);
type.IsNumericType().ShouldBe(expectedResult);
}

[Fact]
public void Test_IsNumericIntegerType()
[Theory]
[InlineData(typeof(string), false)]
[InlineData(typeof(char), false)]
[InlineData(typeof(bool), false)]
[InlineData(typeof(IntPtr), false)]
[InlineData(typeof(UIntPtr), false)]
[InlineData(typeof(byte), true)]
[InlineData(typeof(sbyte), true)]
[InlineData(typeof(short), true)]
[InlineData(typeof(ushort), true)]
[InlineData(typeof(int), true)]
[InlineData(typeof(uint), true)]
[InlineData(typeof(long), true)]
[InlineData(typeof(ulong), true)]
[InlineData(typeof(Int128), true)]
[InlineData(typeof(UInt128), true)]
[InlineData(typeof(BigInteger), true)]
[InlineData(typeof(float), false)]
[InlineData(typeof(double), false)]
[InlineData(typeof(Half), false)]
[InlineData(typeof(decimal), false)]
public void Test_IsNumericIntegerType(Type type, bool expectedResult)
{
typeof(string).IsNumericIntegerType().ShouldBe(false);
typeof(char).IsNumericIntegerType().ShouldBe(false);

typeof(byte).IsNumericIntegerType().ShouldBe(true);
typeof(sbyte).IsNumericIntegerType().ShouldBe(true);
typeof(short).IsNumericIntegerType().ShouldBe(true);
typeof(ushort).IsNumericIntegerType().ShouldBe(true);
typeof(int).IsNumericIntegerType().ShouldBe(true);
typeof(uint).IsNumericIntegerType().ShouldBe(true);
typeof(long).IsNumericIntegerType().ShouldBe(true);
typeof(ulong).IsNumericIntegerType().ShouldBe(true);

typeof(float).IsNumericIntegerType().ShouldBe(false);
typeof(double).IsNumericIntegerType().ShouldBe(false);
typeof(decimal).IsNumericIntegerType().ShouldBe(false);

typeof(BigInteger).IsNumericIntegerType().ShouldBe(true);
type.IsNumericIntegerType().ShouldBe(expectedResult);
}

[Fact]
public void Test_IsNumericFloatType()
[Theory]
[InlineData(typeof(string), false)]
[InlineData(typeof(char), false)]
[InlineData(typeof(bool), false)]
[InlineData(typeof(IntPtr), false)]
[InlineData(typeof(UIntPtr), false)]
[InlineData(typeof(byte), false)]
[InlineData(typeof(sbyte), false)]
[InlineData(typeof(short), false)]
[InlineData(typeof(ushort), false)]
[InlineData(typeof(int), false)]
[InlineData(typeof(uint), false)]
[InlineData(typeof(long), false)]
[InlineData(typeof(ulong), false)]
[InlineData(typeof(Int128), false)]
[InlineData(typeof(UInt128), false)]
[InlineData(typeof(BigInteger), false)]
[InlineData(typeof(float), true)]
[InlineData(typeof(double), true)]
[InlineData(typeof(Half), true)]
[InlineData(typeof(decimal), true)]
public void Test_IsNumericFloatType(Type type, bool expectedResult)
{
typeof(string).IsNumericFloatType().ShouldBe(false);
typeof(char).IsNumericFloatType().ShouldBe(false);

typeof(byte).IsNumericFloatType().ShouldBe(false);
typeof(sbyte).IsNumericFloatType().ShouldBe(false);
typeof(short).IsNumericFloatType().ShouldBe(false);
typeof(ushort).IsNumericFloatType().ShouldBe(false);
typeof(int).IsNumericFloatType().ShouldBe(false);
typeof(uint).IsNumericFloatType().ShouldBe(false);
typeof(long).IsNumericFloatType().ShouldBe(false);
typeof(ulong).IsNumericFloatType().ShouldBe(false);

typeof(float).IsNumericFloatType().ShouldBe(true);
typeof(double).IsNumericFloatType().ShouldBe(true);
typeof(decimal).IsNumericFloatType().ShouldBe(true);

typeof(BigInteger).IsNumericFloatType().ShouldBe(false);
type.IsNumericFloatType().ShouldBe(expectedResult);
}

[Fact]
Expand Down

0 comments on commit 645c5e4

Please sign in to comment.