2

I have two classes, one used for float and one used for int. Their code is exactly the same and I would like to write a template class that would be compatible with both int and float in order not to copy this code with just a different type.

Here is my class :

namespace XXX.Schema
{
    public abstract class NumericPropDef< NumericType > : PropDef
        where NumericType : struct, IComparable< NumericType >
    {
        public NumericType? Minimum { get; protected set; }

        public NumericType? Maximum { get; protected set; }

        public NumericType? Default { get; protected set; }

        public NumericPropDef() : base() { }

        public void SetMinimum( NumericType? newMin )
        {
            if( null != newMin && null != Maximum && (NumericType) newMin > (NumericType) Maximum )
                throw new Exception( "Minimum exceeds maximum" );
            Minimum = newMin;
        }

        public void SetMaximum( NumericType? newMax )
        {
            if( null != newMax && null != Minimum && (NumericType) newMax < (NumericType) Minimum )
                throw new Exception( "Maximum is below minimum" );
            Maximum = newMax;
        }

        public void SetDefault( NumericType? def )
        {
            Default = def;
        }
    }
}

But for reasons I don't know, I'm getting the following error :

error CS0019: Operator '>' cannot be applied to operands of type 'NumericType' and 'NumericType'

I'm used to C++ templates, but not to C# templates so I'm a bit lost here. What could be the reason of that ? Thank you.

Virus721
  • 8,061
  • 12
  • 67
  • 123
  • 1
    Look at the first answer: http://stackoverflow.com/questions/2357410/having-to-implement-a-generic-less-than-and-greater-than-operation – Gusman Feb 06 '16 at 19:28
  • 1
    Default is `NumericType?` (can be nullable) which is different from `NumericType` – Orel Eraki Feb 06 '16 at 19:28

1 Answers1

5

Without specifying anything else, any generic parameter (such as your NumericType) is assumed to have the same capabilities as System.Object. Why? Well, because users of your class might pass System.Object to the NumericType parameter. So, it is not guaranteed that the type passed to that generic parameter supports a > operator, and hence the compiler doesn't allow you to use it.

Now, you have somewhat restricted NumericType, in that you require that any type passed to NumericType implement IComparable<T> and is a structure. However, neither of these restrictions guarantees that there is a > operator, so you still cannot use it.

In your particular case, you might want to use the CompareTo method, whose availability on any type passed to NumericType is guaranteed by your requirement that the type implement IComparable<T>. Note, however, that like this, your class can also be used for loads of other types that have nothing to do with numbers, if that poses a problem to you.

In general, your particular quest for finding a restriction that lets users supply a numeric type cannot be properly answered in C#, as numeric types in C# (or the CLI in general) do not inherit from a common base class for numeric types.

O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114
  • 1
    ...and the solution to this issue is to use the `Comparer.Default.Compare` method – Lucas Trzesniewski Feb 06 '16 at 19:35
  • 1
    Thanks for your help. I thought that IComparable was ensuring the comparison operators were implemented. – Virus721 Feb 06 '16 at 19:36
  • 1
    @Virus721: If that were the case, the respective operators would be listed in an operators section in the [docs for `IComparable`](https://msdn.microsoft.com/en-us/library/4d7sx9hd%28v=vs.110%29.aspx). – O. R. Mapper Feb 06 '16 at 19:40
  • 1
    @LucasTrzesniewski: Does that provide any advantages over the `CompareTo` method I mentioned in the answer? – O. R. Mapper Feb 06 '16 at 19:41
  • 1
    @O.R.Mapper the only advantage I can think of is that you don't have to check for `null` (which doesn't apply to structs anyway) - I wrote that comment before you added the `CompareTo` part. – Lucas Trzesniewski Feb 06 '16 at 19:44