views:

314

answers:

7

I would like to create a function that checks if a numeric value passed as an argument has a value greater than zero. Something like this:

public bool IsGreaterThanZero(object value)
{
    if(value is int)
    {
        return ((int)value > 0);
    }
    else if(value is float)
    {
        // Similar code for float
    }

    return false;
}

Can I try to cast the object passed as the function's argument to one numeric data type so I can then compare it to zero rather than checking for each type in my if statement? If the cast fails I would return false. Is there a better(read shorter, more readable) way to do this?

Edit: Some have asked about if I know the type will be a numeric, why the object etc. I hope this makes things clearer.

This function would be part of a Silverlight converter that implements the IValueConverter interface which has a convert signature of

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

A first, I only wanted the converter to work with ints but my imagination started to run wild and think what if I have floating point numbers and other numeric types. I wanted to make the converter as flexible as possible. Initially I thought all this extra information would get in the way of what I wanted to do so I didn't include it in my question.

+1  A: 

Try:

double tempValue;
if(double.TryParse(value.ToString(), out tempValue)
{
  return (tempValue > 0)
}
else 
{
  return false;
}
Mike Mooney
This is not particularly efficient, since it's going to string, then to double...
Reed Copsey
yeah, but I figure the other alternative is to use Convert.ToDouble or something like that, which (A) could throw an exception and (B) I don't really know how efficient that one is either. Anyhow, it would be ideal if .NET had a Covert.TryToDouble that returned a boolean instead of throwing an exception, but that doesn't seem to exist
Mike Mooney
@Mike: See my answer - it basically handles that case, without the string conversions...
Reed Copsey
@Reed: in your answer, wouldn't the caller be able to pass in a string like "notANumber", have it pass the IConvertable test, and then throw InvalidCastException. As far as efficiency, one of my main concerns is avoiding exceptions based on the input data.
Mike Mooney
Actually see my answer and if can't figure out where to go from my simple and efficient answer, check out Reed's "For Dummies" answer.
Langdon
Again, wouldn't those Convert functions would throw an exception if the input was a string that couldn't be coverted to an numeric value?
Mike Mooney
+1  A: 

Why not just Convert.ToDouble or Convert.ToDecimal and then do the comparison? Seems like that would handle most types that someone might pass in.

Langdon
+10  A: 

My preference would be:

public bool IsGreaterThanZero(object value)
{
    if(value is IConvertible)
    {
        return Convert.ToDouble(value) > 0.0;
    }

    return false;
}

This will handle all IConvertible types safely (which includes all floating point and integer types in the framework, but also any custom types).

Reed Copsey
Wouldn't this throw an exception if the caller passed in a non-numeric string value?
Mike Mooney
@Mike: Potentially- It could be handled, if required, via a try/catch, though.
Reed Copsey
@Mike: The OP specified that this would be a numeric value, though - if that's true, the above is fine. If it's not, you'd need exception handling...
Reed Copsey
My point is, I would expect throwing and catching an exception to be a far worse performance impact than a string parse. A non-numeric string should be expected as common input to the function (since there is nothing to restrict it or avoid it), then it's not really an exception case that should warrant the performance impact of an exception
Mike Mooney
@Mike: THe performance hit is only significant IF the exception is thrown. A try/catch that isn't triggered has almost no perf. hit. If your standard, real case is to handle this without the exception, this will be much better perf. than converting to a string and back each time (since that happens on all of the good data, too).
Reed Copsey
Why the downvoting, btw? Just curious...
Reed Copsey
I upvoted you, Reed. :) Nice solution.
Dave
+10  A: 

Does the caller know the type? If so, how about:

public static bool GreaterThanZero<T>(T value) where T : struct, IComparable<T>
{
    return value.CompareTo(default(T)) > 0;
}

No conversions needed, and should work for any of the built-in numeric types - and any sensible value types you come up with yourself. (For example, this would be fine with Noda Time's Duration struct.)

Note that the caller doesn't have to know the type directly - it may only know it as another type parameter with the same constraints. Admittedly this may not be appropriate for your situation, but I thought I'd mention it anyway. If nothing knows the type at compile-time (and you don't fancy getting dynamic typing to do the job for you in C# 4!) then calling Convert.ToDouble is probably your best bet - just be aware that it may have problems for System.Numerics.BigInteger from .NET 4.0.

Jon Skeet
+2  A: 

You can avoid boxing and unboxing using generics:

Here's the definition of a function

class GenericComparation {
    public static bool IsGreaterThanZero<T>(T value) where T : IComparable<T> {
        // Console.WriteLine(value.GetType().Name)
        return value.CompareTo(default(T)) > 0;
    }
}

Usage:

Console.WriteLine(GenericComparation.IsGreaterThanZero(1));
Console.WriteLine(GenericComparation.IsGreaterThanZero(-1.1));
Console.WriteLine(GenericComparation.IsGreaterThanZero(Decimal.Zero));
Alfred Myers
+3  A: 

Eh? What numeric types do you care about?

public bool IsGreaterThanZero(double value)
{
    return value > 0;
}

These all work ...

    IsGreaterThanZero((int)2);
    IsGreaterThanZero((long)2);
    IsGreaterThanZero((double)2);
    IsGreaterThanZero((float)2);
    IsGreaterThanZero((byte)2);
    IsGreaterThanZero((ulong)2);
Hightechrider
To me this is the best answer. Type safe (no casting exception), efficient (no conversions or try/catches) and covers all bases.
Russell
@Russel: There will be implicit casts on the call site for everything but a double. Check it out with .Net Reflector. It also doesn't work implicitly for Decimal.
Alfred Myers
+1 Hightechrider and +1 Russell: I totally agree with you both.
Sameh Serag
A: 

This simplest and fastest way to compare any numeric type To zero is as follows:

public bool IsGreaterThanZero(object value) 
{ 
    if (value != null && value.GetType().IsValueType)
        return System.Convert.ToDouble(value) > 0;
    return false; 
}
Jim McCurdy
IsValueType doesn't guarantee that the value is numeric. Could be a struct or just plain "object", or an arbitrary string.
Anna Lear