views:

758

answers:

4

I have an Infragistics UltraNumericEditor (version 5.3, quite old) control on a form.

If I set the .Value field to something less than .MinValue or something more than .MaxValue then I get a System.Exception thrown with the following message:

The 'Value' property cannot be set to a value that is outside the range determined by the 'MinValue' and 'MaxValue' properties

The signatures of the relevant fields on UltraNumericEditor are as follows:

public object MinValue { get; set; }
public object MaxValue { get; set; }    
public object Value { get; set; }

This has potential to occur many hundreds of times through our codebase, so rather than check MinValue and MaxValue vs the value we're trying to set every time, I thought I'd subclass the control and put the check there:

public class OurNumericEditor : Infragistics.Win.UltraWinEditors.UltraNumericEditor  
{  
    public object Value  
    {
        get
        {
            return base.Value;
        }
        set
        {
            // make sure what we're setting isn't outside the min or max
            // if it is, set value to the min or max instead

            double min = (double)base.MinValue;
            double max = (double)base.MaxValue;
            double attempted = (double)value;

            if (attempted > max)
                base.Value = max;
            else if (attempted < min)
                base.Value = min;
            else
                base.Value = value;
        }
    }
}

Clearly this works fine when the type of value, MinValue and MaxValue can be casted to doubles, but I would expect an InvalidCastException when that's not possible.

Now I may just be having a blonde moment here but I think it should be possible to write a method that makes use of generics to do the comparison, but I'm struggling to visualise what that might look like.

Any ideas or input at all?

Thanks
Tom

+4  A: 

You could simply cast everything as IComparable and use that interface to do the comparison.

Matt Hamilton
Okay - I've tried casting MinValue, MaxValue and value to IComparable. Then, I write logic that uses IComparable.CompareTo() to decide whether to use MinValue, MaxValue or the value that the calling code actually tried to use. However, if I set .Value to a double, and MinValue and/or MaxValue are integers, IComparable.CompareTo() throws an ArgumentException: "Object must be of type Double." I would imagine I would get the same exception if the types don't match. Any feedback?
tomfanning
The types must match for IComparable. You could try converting them with IConvertible.
configurator
@configurator's right - the types need to match. I wasn't aware that you'd be setting the variables to different underlying types.
Matt Hamilton
+1  A: 

Generics will not help you here, as the controls Value property is not generic either. But you could go with the IConvertible interface to convert the number to what you need for the comparison (double for instance).

Lucero
+2  A: 

You can't make any good use of generics, as you don't know the data type at compile time.

Just use the Convert class to convert any kind numeric data to double values:

double min = Convert.ToDouble(base.MinValue);
double max = Convert.ToDouble(base.MaxValue);
double attempted = Convert.ToDouble(value);

This has the benefit that it also handles cases with mixed data types, like when MinValue is an int and value is a double.

Guffa
+1. Convert.ToAnything() works fine with many cases where naive attempts fail (like a boxed int which fails to cast to double, but is handled by Convert.ToDouble() as it should be).
OregonGhost
I actually started with this implementation myself, but it somehow just didn't feel right to assume that everything going in would be OK being converted to a double.Having said that, double's massive range will cover the vast vast majority of all cases where this code will be used in practice, and the precision issue with floating point numbers won't be a problem in practice either, especially if we set the original value being passed in, rather than something that's been via Convert.ToDouble().Thanks
tomfanning
+1  A: 

This is probably overkill here, and IComparable would probably do the trick in your situation.

But if you really want to strongly type the values accepted by your control, you should probably write something like this :

public OurNumericEditor<T> : Infragistics.Win.UltraWinEditors.UltraNumericEditor  

 public T Value  
    {
        get
        {
            return (T) base.Value;
        }
        set
        {
            // make sure what we're setting isn't outside the min or max
            // if it is, set value to the min or max instead

            double min = (double)MinValue;
            double max = (double)MaxValue;
            double attempted = // explicit conversion code goes here

            if (attempted > max)
                base.Value = max;
            else if (attempted < min)
                base.Value = min;
            else
                base.Value = value;
        }
    }
}
Brann
I like this but you're right, for my particular situation it's overkill. Neat solution though.
tomfanning