Question

I've got a generic class that implements a property called Value which is of type T. This class is primarily used to handle numbers of different types (decimal, float, etc), but because it is impossible to constrain T to numeric types only it could also handle DateTime, string, and anything else you choose to throw at it.

So, in the property setter is there any way I can test if the changed value is negative, in a way that isn't going to fall over or require huge amounts of code or type checking?

The generic class looks a little like this:

public class ValueText<T> 
{
    private T _value;
    private bool _isNeg;

    public bool IsNegative { get { return _isNeg; } }

    public T Value
    {
        get { return _value; }
        set
        {
            //check if the new value is the same as the old value:
            if (EqualityComparer<T>.Default.Equals(value, _value))
                return;

            _value = value;

            _isNeg = ...what?...;

            NotifyPropertyChanged("Value");
        }
    }
}
Was it helpful?

Solution

Yes, it is possible to do this in one line with no type checking. There is one caveat though - this method will not play nice if the concrete type doesn't implement IComparable or IComparable<T>. If you don't implement one of those interfaces then you will get a System.ArgumentException, but this is easily accommodated (especially as it is most likely to occur for one of your own custom types, I don't think there are many BCL types that don't implement it).

All you need is this nifty line of code:

bool isNegative = Comparer<T>.Default.Compare(value, default(T)) < 0;

The real beauty in this one is the default(T) - this is what accommodates strings, DateTimes, etc. The concrete type will get compared to the default value of the type, and for the likes of string or DateTime the Compare() will never return less than zero when comparing to the default.

Check out this sample, which includes an example custom struct so you can see the IComparable in action:

class Program
{

    static void Main(string[] args)
    {

        Console.WriteLine("Comparing different value (and reference) types to zero:");
        Console.WriteLine();
        Console.WriteLine("Checking int '9' : {0}", IsNegative(9));
        Console.WriteLine("Checking int '-9': {0}", IsNegative(-9));
        Console.WriteLine("Checking int '0' : {0}", IsNegative(0));
        Console.WriteLine();
        Console.WriteLine("Checking decimal '9' : {0}", IsNegative(9m));
        Console.WriteLine("Checking decimal '-9': {0}", IsNegative(-9m));
        Console.WriteLine("Checking decimal '0' : {0}", IsNegative(0m));
        Console.WriteLine();
        Console.WriteLine("Checking float '9'  : {0}", IsNegative(9f));
        Console.WriteLine("Checking float '-9' : {0}", IsNegative(-9f));
        Console.WriteLine("Checking float '0'  : {0}", IsNegative(0f));
        Console.WriteLine();
        Console.WriteLine("Checking long '9'  : {0}", IsNegative(9L));
        Console.WriteLine("Checking long '-9' : {0}", IsNegative(-9L));
        Console.WriteLine("Checking long '0'  : {0}", IsNegative(0L));
        Console.WriteLine();
        Console.WriteLine("Checking string '9'   : {0}", IsNegative("9"));
        Console.WriteLine("Checking string '-9'  : {0}", IsNegative("-9"));
        Console.WriteLine("Checking string empty : {0}", IsNegative(string.Empty));
        Console.WriteLine("Checking string null  : {0}", IsNegative((string)null));
        Console.WriteLine();
        Console.WriteLine("Checking DateTime.Now '{0}' : {1}", DateTime.Now, IsNegative(DateTime.Now));
        Console.WriteLine("Checking DateTime.Max '{0}' : {1}", DateTime.MaxValue, IsNegative(DateTime.MaxValue));
        Console.WriteLine("Checking DateTime.Min '{0}' : {1}", DateTime.MinValue, IsNegative(DateTime.MinValue));
        Console.WriteLine();
        Console.WriteLine("Checking positive MyStruct : {0}", IsNegative(new MyStruct() { MainValue = 9 }));
        Console.WriteLine("Checking negative MyStruct : {0}", IsNegative(new MyStruct() { MainValue = -9 }));
        Console.WriteLine("Checking zero MyStruct     : {0}", IsNegative(new MyStruct() { MainValue = 0 }));
        Console.WriteLine();

        Console.ReadKey();
    }

    private static bool IsNegative<T>(T value)
    {
        return Comparer<T>.Default.Compare(value, default(T)) < 0;
    }

    private struct MyStruct : IComparable<MyStruct>, IComparer<MyStruct>
    {
        public int MainValue;

        public int CompareTo(MyStruct other)
        {
            return MainValue - other.MainValue;
        }

        public int Compare(MyStruct x, MyStruct y)
        {
            return x.MainValue - y.MainValue;
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top