tags:

views:

117

answers:

2

Is there a way you can do this ?

I would like to have a collection class of T that would be able to do addition, substraction on the T type. I would like to keep T generic instead of having couple collections with the same code, but different types.

How would you constrain the generic T ?

Example: I would like to define a Collection(of T as IDoMaths). I wouldn't like to create my own integer etc classes with named methods to do the operations, because I think it would be slower. This part of the code is actually called very often and tends to be the bottleneck in perfomance.

+5  A: 

Unfortunately you can't.

There's a workaround which Marc Gravell has implemented as part of MiscUtil (with a more general article too). It's neat, but you do lose static type checking.

In a similar vein (in terms of losing type checking) the new dynamic feature of C# 4.0 lets you use operators in an arbitrary way, only resolving them at execution time:

dynamic x = 10.0;
dynamic y = 3.0;
double z = x / y; // z = 3.3333333 (double arithmetic)

dynamic a = 10;
dynamic b = 3;
int c = a / b; // c = 3 (integer arithmetic)

Just this afternoon I used this to implement a dynamic form of Enumerable.Sum. I'm about to benchmark it. Marc Gravell wrote a blog post about this recently, too.

If you're using VB, it's possible that just turning Option Strict off for the section of code where you want late binding will have the same effect, but I'm not as familiar with VB as I am with C#, I'm afraid.

Jon Skeet
This is a disappointing limitation in the current implementation of generics. Marc's implementation is the best I've seen as well at dealing with the problem. There are a few support articles on connect.microsoft.com related to this. You can find them here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94264 and here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=325177 and here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=338861.
LBushkin
Did you intend the int example to use dynamic at all?
Marc Gravell
Doh - thanks, fixed :)
Jon Skeet
Thank you, my previous search kind of pointed these things out, but I wanted to know better.
Tomas Pajonk
+3  A: 

If you want an alternative solution that's more straightforward but involves a tiny bit more redundancy, you can try something I just whipped up. An advantage here is that it's fully typesafe.

Here's a quick a dirty version that implements + and - operations for int and float. It should be trivial to extend it to include more operations as well as support more primitive types (double, decimal, etc) -or even custom types for that matter. Just replace GenericMath with whatever you need.

class Program
{
    static void Main(string[] args)
    {
        var gsInt = new GenericMath<int,IntOperators>();
        var gsFloat = new GenericMath<float,FloatOperators>();

        var intX = gsInt.Sum( 2, 3 );
        var floatX = gsFloat.Sum( 2.4f, 3.11f );
    }
}

interface IOperators<T>
{
    T Sum( T a, T b );
    T Difference( T a, T b );
}

sealed class IntOperators : IOperators<int>
{
    public int Sum( int a, int b ) { return a + b; }
    public int Difference( int a, int b ) { return a - b; }
}

sealed class FloatOperators : IOperators<float>
{
    public float Sum( float a, float b ) { return a + b; }
    public float Difference( float a, float b ) { return a + b; }
}

class GenericMath<T,Y>
    where Y : IOperators<T>, new()
{
    private readonly static Y Ops = new Y();

    public T Sum( T a, T b )
    {
        return Ops.Sum( a, b );
    }

    public T Difference( T a, T b )
    {
        return Ops.Difference( a, b );
    }
}
LBushkin
Full disclosure - you need to provide the IOperators implemeting type to any instances of classes that will perform generic math operations.
LBushkin