Is there a C# generic constraint for "real number" types?

22,072

Solution 1

You can't define such a constraint, but you could check the type at runtime. That won't help you for doing calculations though.

If you want to do calculations, something like this would be an option:

class Calculations<T, S> where S: Calculator<T>, new()
{
    Calculator<T> _calculator = new S();

    public T Square(T a)
    {
        return _calculator.Multiply(a, a);
    }

}

abstract class Calculator<T>
{
    public abstract T Multiply(T a, T b);
}

class IntCalculator : Calculator<int>
{
    public override int Multiply(int a, int b)
    {
        return a * b;
    }
}

Likewise, define a FloatCalculator and any operations you need. It's not particularly fast, though faster than the C# 4.0 dynamic construct.

var calc = new Calculations<int, IntCalculator>();
var result = calc.Square(10);

A side-effect is that you will only be able to instantiate Calculator if the type you pass to it has a matching Calculator<T> implementation, so you don't have to do runtime type checking.

This is basically what Hejlsberg was referring to in this interview where the issue is discussed. Personally I would still like to see some kind of base type :)

Solution 2

This is a very common question; if you are using .NET 3.5, there is a lot of support for this in MiscUtil, via the Operator class, which supports inbuilt types and any custom types with operators (including "lifted" operators); in particular, this allows use with generics, for example:

public static T Sum<T>(this IEnumerable<T> source) {
    T sum = Operator<T>.Zero;
    foreach (T value in source) {
        if (value != null) {
            sum = Operator.Add(sum, value);
        }
    }
    return sum;
}

Or for another example; Complex<T>

Solution 3

This is a known problem, since none of the arithmetic classes arrive from the same class. So you cannot restrict it.

The only thing you could do is

where T : struct

but thats not exactly what you want.

Here is a link to the specific issue.

Arithmetic types like int,double,decimal should implement IArithmetic<T>

Solution 4

You actually can do this, although the solution is tedious to set up, and can be confusing to devs who are not aware of why it was done. (so if you elect to do it document it thououghly!)...

Create two structs, called say, MyInt, and MyDecimal which act as facades to the CTS Int32, and Decimal core types (They contain an internal field of that respective type.) Each should have a ctor that takes an instance of the Core CTS type as input parameter..

Make each one implement an empty interface called INumeric

Then, in your generic methods, make the constraint based upon this interface. Downside, everywhere you want to use these methods you have to construct an instance of the appropriate custom type instead of the Core CTS type, and pass the custom type to the method.

NOTE: coding the custom structs to properly emulate all the behavior of the core CTS types is the tedious part... You have to implement several built-in CLR interfaces (IComparable, etc.) and overload all the arithmetic, and boolean operators...

Solution 5

You can get closer with implementing few more

public class Point<T> where T : struct, IComparable, IFormattable, IConvertible, 
                                IComparable<T>, IEquatable<T> {   
}

The signature conforms to DateTime too. I'm not sure if you will be able to specify more types from the framework. Anyway this only solves part of the problem. To do basic numeric operations you will have to wrap your numeric types and use generic methods instead of standard operators. See this SO question for a few options.

Share:
22,072

Related videos on Youtube

Syndog
Author by

Syndog

Updated on July 09, 2022

Comments

  • Syndog
    Syndog almost 2 years

    Possible Duplicate:
    C# generic constraint for only integers

    Greets!

    I'm attempting to set up a Cartesian coordinate system in C#, but I don't want to restrict myself to any one numerical type for my coordinate values. Sometimes they could be integers, and other times they could be rational numbers, depending on context.

    This screams "generic class" to me, but I'm stumped as to how to constrict the type to both integrals and floating points. I can't seem to find a class that covers any concept of real numbers...

    public class Point<T> where T : [SomeClassThatIncludesBothIntsandFloats?]  {
        T myX, myY;
    
        public Point(T x, T y) {
            myX = x;
            myY = y;
        }
    }
    
    Point<int> pInt = new Point<int>(5, -10);
    Point<float> pFloat = new Point<float>(3.14159, -0.2357);
    

    If I want this level of freedom, am I electing for a "typeof(T)" nightmare when it comes to calculations inside my classes, weeding out bools, strings, objects, etc? Or worse, am I electing to make a class for each type of number I want to work with, each with the same internal math formulae?

    Any help would be appreciated. Thanks!

    • Eric Lippert
      Eric Lippert over 14 years
      This is a fairly frequently requested feature. We're considering it as a possibility for a hypothetical future release of the compiler/runtime, but it is not super high on the priority list, so I would not construe this as any kind of promise. Remember, we have HUNDREDS of possible features and any given release only gets a handful of them. It's certainly on our radar though.
    • Syndog
      Syndog over 14 years
      That's good to know, Eric. I'm very new to C#, but I have roots in Java, so it's very much like jumping dimensions... similar, but different enough to make you go "huh?" once in a while. ;)
    • Syndog
      Syndog over 14 years
      To everyone else, thanks so much for all your responses. You guys are all over this! No wonder anytime I Google a C# question, stackoverflow.com ranks so prominently in the results.
    • dmihailescu
      dmihailescu almost 13 years
      this is not and ironclad solution, but it will narrow the scope of the type parameter significantly: public class Point<T> where T : IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>,struct {...
    • Martin Mulder
      Martin Mulder almost 11 years
      I added some code here (codereview.stackexchange.com/questions/26022/…) which might help you.
  • Syndog
    Syndog over 14 years
    Right, that makes sense. Basically wrap my "primitive" types in classes that implement a common interface, then constrict based on that. Thanks, Thor!
  • Syndog
    Syndog over 14 years
    Well, the calculations are actually identical, regardless of whether or not they're implemented using integer or floating-point values. Otherwise I'd just make two separate classes that implement their respective types without any generics or inheritance at all. But since the formulas are identical, I don't want to duplicate code between classes. Thanks for your response!
  • Syndog
    Syndog over 14 years
    Hey Stan, just wanted to let you know that helps quite a bit. In a single stroke, making T inherit from struct eliminates the need for a run-time check for all value types. Thanks, bud!
  • Marc Gravell
    Marc Gravell over 14 years
    Note that in .NET 3.5 there are still things you can do with generics - see my answer for more.
  • Thorarin
    Thorarin over 14 years
    Interesting. Looks like it uses the LINQ expression tree functionality, but immediately evaluates each bit?
  • Marc Gravell
    Marc Gravell over 14 years
    Internally, it uses an expression tree to pre-compile (once-only per-type) a delegate that can do the arithmetic.
  • weberc2
    weberc2 over 11 years
    Your link results in "page not found".