Search code examples
c#asp.netcastingcompare

How to compare different types of objects


Looking for a way to find is object between two objects. Tried to convert integer to decimal using

static bool Between(object value, object low, object high)
  {
    if (value == null && low == null && high == null)
      return false;

    if (value is int || low is int || high is int ||
      value is decimal || low is decimal || high is decimal ||
      value is double || low is double || high is double ||
      value is int? || low is int? || high is int? ||
      value is decimal? || low is decimal? || high is decimal? ||
      value is double? || low is double? || high is double? )
     return (decimal)(value ?? 0) >= (decimal)(low ?? 0) && (decimal)(value ?? 0) <= (decimal)(high ?? 0);

    if (value is DateOnly || low is DateOnly || high is DateOnly ||
      value is DateOnly? || low is DateOnly? || high is DateOnly?)
      return (DateOnly)(value ?? DateOnly.MinValue) >= (DateOnly)(low ?? DateOnly.MinValue) && (DateOnly)(value ?? 0) <= (DateOnly)(high ?? DateOnly.MinValue);

    if (value is string || low is string || high is string ||
      value is char || low is char || high is char
      value is string || low is string || high is string ||
      value is char? || low is char? || high is char? )
    {
      string av = (string)(value ?? "");
      string slow = (string)(low ?? "");
      string shigh = (string)(high ?? "");
      return av.CompareTo(slow) >= 0 && av.CompareTo(shigh) <= 0;
    }
    throw new ArgumentException("Incompatible argument types");
  }

Using mixed int and decimal arguments

 Between((int)1 , (decimal)1, (decimal) 2 )

throws exception

Cannot cast integer to decimal

How fix this methid it so it works if arguments are int, decimal, double, int?, decimal? or double? in any combinations. Can using dynamic arument tupes insted of object type make it easier?

Using ASP .NET 8 MVC with latest C#


Solution

  • I would suggest to use Convert.ChangeType method, that does very well mapping between various number types, so it is safe to pick common, most inclusive numeric type, such as decimal and use it like below:

    bool IsBetweenForNumbers(object value, object low, object high, out bool isBetween)
    {
        try
        {
            var cValue = (decimal)Convert.ChangeType(value, typeof(decimal));
            var cLow = (decimal)Convert.ChangeType(low, typeof(decimal));
            var cHigh = (decimal)Convert.ChangeType(high, typeof(decimal));
    
            isBetween = cLow < cValue && cHigh > cValue;
            return true;
        }
        catch
        {
            isBetween = false;
            return false;
        }
    }
    

    Now it is very flexible, it correctly handles such use cases:

    var r1 = IsBetweenForNumbers((int)1, (decimal)1, (decimal)2, out var b1);
    var r2 = IsBetweenForNumbers("1", 2, 5M, out var b2);
    var r3 = IsBetweenForNumbers(3F, 2M, 5, out var b3);
    

    This method should be incorporated in yours to avoid problems you have.

    Reference: Convert.ChangeType