The fastest way to check the numerical value of a nested primitive integral type in C #

I need to write a method with the following semantics:

/// <summary>
/// Checks if <paramref name="x"/> is a boxed instance of a primitive integral type
/// whose numerical value equals to <paramref name="y"/>.
/// </summary>
/// <param name="x">An object reference. Can be <c>null</c>.</param>
/// <param name="y">A numerical value of type <see cref="ulong"/> to compare with.</param>
/// <returns>
/// <c>true</c> if <paramref name="x"/> refers to a boxed instance of type 
/// <see cref="sbyte"/>, <see cref="short"/>, <see cref="int"/>, <see cref="long"/>, 
/// <see cref="byte"/>, <see cref="ushort"/>, <see cref="uint"/>, or <see cref="ulong"/>, 
/// whose numerical value equals to the numerical value of <paramref name="y"/>; otherwise, <c>false</c>.
/// </returns>
/// <remarks>
/// <para>
/// This method checks only for numeric equality, even if its arguments are of different runtime types
/// (e.g. <c>2L</c> is considered to be equal to <c>2UL</c>).
/// </para>
/// <para>
/// This method returns <c>false</c> if <paramref name="x"/> is <c>null</c>
/// or refers to an instance of a reference type or a boxed instance of a value type except
/// the primitive integral types listed above (e.g. it returns <c>false</c> if <paramref name="x"/>
/// refers to a boxed instance of an <c>enum</c> type, <see cref="bool"/>, <see cref="char"/>, <see cref="IntPtr"/>,
/// <see cref="UIntPtr"/>, <see cref="float"/>, <see cref="double"/>, <see cref="decimal"/>, or <see cref="BigInteger"/>).
/// </para>
/// <para>
/// This method should not throw any exceptions, or cause any observable side-effects
/// (e.g. invoke a method that could modify the state of an object referenced by <paramref name="x"/>). 
/// </para>
/// </remarks>
[Pure]
public static bool NumericalEquals(object x, ulong y)

The implementation should be as fast as possible (provided that the source data does not have the expected offset for certain types or values โ€‹โ€‹of the parameter x) and you should not use code unsafeor P / Invoke. Of course, among the fastest implementations, I would prefer the simplest and shortest.

My solution is this:

public static bool NumericalEquals(object x, ulong y)
{
    if (x is sbyte)
    {
        sbyte z = (sbyte)x;
        return z >= 0 && y == (ulong)z;
    }

    if (x is short)
    {
        short z = (short)x;
        return z >= 0 && y == (ulong)z;
    }

    if (x is int)
    {
        int z = (int)x;
        return z >= 0 && y == (ulong)z;
    }

    if (x is long)
    {
        long z = (long)x;
        return z >= 0 && y == (ulong)z;
    }

    if (x is byte)
    {
        return y == (byte)x;
    }

    if (x is ushort)
    {
        return y == (ushort)x;
    }

    if (x is uint)
    {
        return y == (uint)x;
    }

    if (x is ulong)
    {
        return y == (ulong)x;
    }

    return false;
}

Could you suggest a better approach?

+4
source share
3 answers

, is, , JIT RuntimeTypeHandle x (, ) (, mov, ). , , , .

+2

, :

public static bool NumericalEquals(object x, ulong y)
{
    var unsigned = (x as byte?) ?? (x as ushort?) ?? (x as uint?) ?? (x as ulong?);
    if (unsigned.HasValue)
    {
        return (unsigned.Value == y);
    }

    var signed = (x as sbyte?) ?? (x as short?) ?? (x as int?) ?? (x as long?);
    return (signed.HasValue) && (signed.Value >= 0) && ((ulong) signed.Value == y);
}

3 (, object sbyte? long?, ulong), Nullable<T> ab, , , .

[]

, : is . - 1 is 2 cast. , , .

[edit 2]

, :

public static bool NumericalEquals(object x, ulong y)
{
    if (x.GetHashCode() != y.GetHashCode()) return false;

    ...
}
0

, , . Type.GetTypeCodeImpl, .NET Framework, , , 5 switch ( ). , TypeCode .

public static bool NumericalEquals(object x, ulong y)
{
  if (x == null)
    return false;

  Type type = x.GetType();
  if (type.IsEnum)
    return false;

  switch (Type.GetTypeCode(type))
  {
  case TypeCode.Byte:
    return (byte)x == y;

  ...other cases here

  default:
    return false;
  }
}

You can avoid the call IsEnumby wrapping the block in try/ catchto handle the exception that will be thrown only if a boxed enum is provided as input. This can improve the performance of expected cases with little expense of a slower result falsefor boxed listings.

-2
source

Source: https://habr.com/ru/post/1546341/


All Articles