Define a generic that implements the + operator [duplicate]
Asked Answered
D

2

13

Possible Duplicate:
Solution for overloaded operator constraint in .NET generics

I have a problem I’m working on, currently it is working for ints but i want it to work for all classes that can be added using the + operator. Is there any way to define this in the generic? For example,

public List<T> Foo<T>() where T : ISummable

Is there any way to do this?

EDIT:
Performance of passing in a delegate to do the summing instead of using += with a type of Int was 540% slower at best. Investigating possible other solution

Final solution:
Thank you all for your suggestions. I ended up with a solution which is not too slow and enforces the checking at compile time. I cannot take full credit as a colleague helped me arrive at this. Anyway, here it is:

Implement an interface with all of the required operators on it in the form of functions

public interface IFoo<InputType, OutputType>
{
    //Adds A to B and returns a value of type OutputType
    OutputType Add(InputType a, InputType b);
    //Subtracts A from B and returns a value of type OutputType
    OutputType Subtract(InputType a, InputType b);
}

Create the class you want to define, but instead of the Where clause, use a dependency injected instance of the IFoo interface. the OutputType will most often be double because the nature of the operations is mathematical.

public class Bar<T>
{
    private readonly IFoo<T,double> _operators;

    public Bar(IFoo<T, double> operators)
    {
        _operators = operators;
    }
}

now when you use this class, you define the rules for operation like this:

private class Foo : IFoo<int, double>
{
    public double Add(int a, int b)
    {
        return (double)(a+b);
    }
    public double Subtract(int a, int b)
    {
        return (double)(a-b);
    }
}

then you would use it like this:

Foo inttoDoubleOperations = new Foo();
Bar myClass = new Bar(Foo);

that way all the operations are enforced at compile time :)

enjoy!

Decca answered 30/8, 2010 at 6:30 Comment(9)
No, not directly. There is an article on CodeProject however that simulates this.Cumbrance
Thanks for your reply. Can you send me a link to the solution?Decca
Why not have method in ISummable<T> that can add two T such as T Add(T first, T second)? Using + operator for addition would IMO involve reflection invoke op_Addition method.Ivanaivanah
Vinay, See Barts comments for the answer to your question. If i implement my own interface called ISummable, i cant get Ints etc to work because they dont implement that interfaceDecca
@Ieppie: Do you mean Operator Overloading with Generics? This is outdated: today, you can do the same much easier with dynamic, and it’s the least useful workaround for the problem at hand.Tempietempla
@Timwi: Except the fact that dynamic will be a lot slower. So it is not outdated.Cumbrance
@Ieppie: “a lot slower”? Have you actually measured it? Of course it’s going to be slower, but for 99.9% of usecases it makes no difference.Tempietempla
@leppie. I asked for a link assuming that you had posted your comment already posessing the location of the project. I see now however that your response was in fact almost as useful as the famous 'Google it', and only slightly more helpful than 'I saw it on the internet once'. I have however since located the project and Timwi, its outdated. Not only that, its slower than the solution i came up with.Decca
@TerrorAustralis: If I had the url on hand, I would have posted it. The fact that I recall seeing it a few years back, does not mean I still possess the link.Cumbrance
T
11

This is a pretty commonly requested new feature for C#: the ability to specify more generic parameter constraints than the ones we already have. Operators are among the most frequently asked. However, C# does not currently support this.

Possible workarounds:

  • Pass a delegate to any method that needs to do addition. This is the most type-safe option, but of course it’s annoying if you need to call such a method often. For example:

    public class Generic<T> {
        public void DoSomething(T anItem, T anotherItem, Func<T, T, T> add) {
            // instead of
            Blah(anItem + anotherItem);
            // have to write:
            Blah(add(anItem, anotherItem));
        }
    }
    
    Generic<int> genInt = ...;
    // and then instead of ...
    genInt.DoSomething(1, 2);
    // have to write:
    genInt.DoSomething(1, 2, (a, b) => a + b);
    
  • Declare your own interface IAddable. Then you can use it as a generic type parameter constraint, but obviously you can’t use int as the parameter then. You would have to use a struct of your own that contains just an int and which implements IAddable:

    public interface IAddable<T> {
        T Add(T other);
    }
     
    public struct Integer : IAddable<Integer> {
        public int Value;
        public Integer(int value) { Value = value; }
        public Integer Add(Integer other) { return new Integer(Value + other.Value); }
    }
    
    // then instead of
    Generic<int> blah = ...;
    // have to write:
    Generic<Integer> blah = ...;
    
  • dynamic. Another possible workaround is to use dynamic, but this is rather hacky and completely unsafe: it will let you pass in any type and call any method or operator, and only crash at runtime, not at compile-time.

Tempietempla answered 30/8, 2010 at 6:36 Comment(1)
Thanks, i may end up going with the passing a delegate approach. It seems like a reasonable workaround and wont add too much effort on the users part. Thanks mate!Decca
P
3

In C# 4.0 is new keyword dynamic that allow you to perform this at runtime. In previous versions it was possible but too shady and tricky for me. But you can allways pass a delegate that will perform additions inside generic. Otherwise it is not possible because there is no ISummable, IAdditive and generally speaking no way to know is something is additive* at compilation time. If you wish some further comments I will add it later. BR.

  • I mean, except for making you own IAdditive and mark some types with them, but It won't work for example with ints.
Proxy answered 30/8, 2010 at 6:34 Comment(1)
Thanks for your reply! You hit the nail right on the head with your comment about IAdditive. I cant work it for ints and other pre-implemented classes/structsDecca

© 2022 - 2024 — McMap. All rights reserved.