Is there a C# generic constraint for "real number" types? [duplicate]
Asked Answered
F

8

24

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!

Furman answered 28/8, 2009 at 18:18 Comment(5)
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.Regionalism
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. ;)Furman
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.Furman
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 {...Pish
I added some code here (codereview.stackexchange.com/questions/26022/…) which might help you.Tammy
W
16

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 :)

Wishbone answered 28/8, 2009 at 18:26 Comment(2)
Right, that makes sense. Basically wrap my "primitive" types in classes that implement a common interface, then constrict based on that. Thanks, Thor!Furman
Note that in .NET 3.5 there are still things you can do with generics - see my answer for more.Narcolepsy
N
13

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>

Narcolepsy answered 3/9, 2009 at 22:3 Comment(2)
Interesting. Looks like it uses the LINQ expression tree functionality, but immediately evaluates each bit?Wishbone
Internally, it uses an expression tree to pre-compile (once-only per-type) a delegate that can do the arithmetic.Narcolepsy
D
7

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>

Donnelly answered 28/8, 2009 at 18:21 Comment(2)
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!Furman
Your link results in "page not found".Kubiak
D
3

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...

Delusive answered 28/8, 2009 at 19:11 Comment(0)
H
1

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.

Harod answered 28/12, 2012 at 17:23 Comment(0)
B
0

This might be helpful. You have to use a generic class to achieve what you want.

Bocanegra answered 28/8, 2009 at 18:24 Comment(0)
E
0

C# doesn't currently allow type constraints on value types. i asked a related question not too long ago.

Enum type constraints in C#

Expense answered 28/8, 2009 at 18:28 Comment(0)
S
0

Would this not lend itself to having seperate classes implementing IPoint?

Something like:

public interface IPoint<T>  
{
    T X { get; set; }
    T Y { get; set; }
}

public class IntegerPoint : IPoint<int>
{

    public int X { get; set; }
    public int Y { get; set; }
}

As the calculations will have to differ in each implementation anyway right?

Dan#

Schiedam answered 28/8, 2009 at 18:40 Comment(1)
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!Furman

© 2022 - 2024 — McMap. All rights reserved.