2

There are some tricks to enforce a generic class to work only with numeric types (see this)

I am creating a library where I end up writing where T : struct, IComparable ... in many class definitions. I want to create an empty interface like this:

public interface INumeric<T> 
    where T :
        struct, 
        IComparable,
        IComparable<T>,
        IConvertible,
        IEquatable<T> { }

and then implement that interface in my generic class:

public struct StepSize<T> : INumeric<T>

but when I try to compare a number with

if (value.CompareTo(default(T)) <= 0)

I get the error:

'T' does not contain a definition for 'CompareTo' ...

Why am I getting the error? I am restricting T's type in the interface already, so T must be IComparable.

EDIT: here the two classes

namespace NumericalAlgorithms
{
    using System;

    public interface INumeric<T>
        where T :
            struct, 
            IComparable,
            IComparable<T>,
            IConvertible,
            IEquatable<T>
    { }
}

and

namespace NumericalAlgorithms.NumericalMethods
{
    using System;

    public struct StepSize<T> : INumeric<T>
    {
        public T Value
        {
            get;
            private set;
        }

        public StepSize(T value)
            : this()
        {
            if (value.CompareTo(default(T)) <= 0)
                throw new Exception("The step size must be greater than zero.");

            this.Value = value;
        }
    }
}
Community
  • 1
  • 1
gire
  • 1,105
  • 1
  • 6
  • 16
  • You could try casting `T` to an `IComparible`. Because of your where restrictions, it should be a valid cast. – ryanyuyu Feb 18 '15 at 14:37
  • Your code works for me. Show us the code which causes this error. Assuming you have all the constraints redefined in `StepSize` too. – Sriram Sakthivel Feb 18 '15 at 14:38
  • Your interface constraints would also match `DateTime`. Not sure if desired. `public struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable, IEquatable` – dognose Feb 18 '15 at 14:38
  • The compiler doesn't recognize a constraint in the way that you're expecting. Constraints aren't recognized as implementations of the constrained interface. In order to do what you want to do, you'll have to implement each interface member explicitly. – Ian P Feb 18 '15 at 14:44
  • @dognose I guess I can live with the fact that it will be not perfect. Thanks for the heads-up. – gire Feb 18 '15 at 14:46
  • @IanP would that happen even if INumeric is an abstract class instead of an interface? – gire Feb 18 '15 at 15:00
  • @gire I would guess that would be the case, but I haven't tried it. – Ian P Feb 18 '15 at 15:11

1 Answers1

1

Try to replace

public struct StepSize<T> : INumeric<T>

by

public struct StepSize<T> : INumeric<T>
where T :
    struct, 
    IComparable,
    IComparable<T>,
    IConvertible,
    IEquatable<T>
schglurps
  • 1,387
  • 1
  • 14
  • 26
  • This is exactly what I am trying to avoid, since many of the classes in the library will be generic (but would require a numeric type) – gire Feb 18 '15 at 14:45
  • @gire The *usage (requirement)* of `INumeric` in the definition of struct `StepSize` doesn't mean that `T` automatically gets the same requirements. On the contrary, the `T` in `StepSize` can be any type. The using of the same `T` in `: INumeric` is where `T` suddenly becomes restricted, and that would produce a compile error (I would expect). – Maarten Feb 18 '15 at 14:49