39

is there some 'where' type contraints in can add to make the follwing code compile ?

public class Plus<T> : BinaryOperator<T> where T : ...
{
    public override T Evaluate(IContext<T> context)
    {
        return left.Evaluate(context) + right.Evaluate(context);
    }
}

Thanks :)

Camilo Martin
  • 37,236
  • 20
  • 111
  • 154
  • 4
    Actually, you can't. See here: http://stackoverflow.com/questions/147646/solution-for-overloaded-operator-constraint-in-net-generics – dlev May 13 '11 at 20:01
  • 2
    This is a frequently requested feature but it does not exist today; there's no way to genericize over the existence of a *static* method, and overloaded operators are always static. – Eric Lippert May 13 '11 at 20:37
  • To add to eric's statement go down the rabbit hole, operators don't have to just take T, they don't even have to return it! As such, despite really wanting it, I'd be happy to wait for it to be done right... – ShuggyCoUk May 15 '11 at 13:27
  • Possible duplicate of [Solution for overloaded operator constraint in .NET generics](https://stackoverflow.com/questions/147646/solution-for-overloaded-operator-constraint-in-net-generics) – Wai Ha Lee Nov 14 '19 at 08:33

5 Answers5

27

There are no such devices in C#. A few options are available, though:

So either:

return (dynamic)left.Evaluate(context) + (dynamic)right.Evaluate(context);

or

return Operator.Add(left.Evaluate(context), right.Evaluate(context));
Camilo Martin
  • 37,236
  • 20
  • 111
  • 154
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
8

In C# 11 and .NET 7, there is a feature exactly for this (see Microsoft Docs). It would have to go as follow:

public interface IAddable<T> where T : IAddable<T>
{
    static abstract T operator +(T left, T right);
}

public class Foo : IAddable<Foo>
{
    public static Foo operator +(Foo left, Foo right)
    {
        /* Something */
    }
}
nrmontagne
  • 151
  • 1
  • 5
  • Can T be int? If not, is there a way to allow int? – D. A. Oct 19 '22 at 23:57
  • @D.A. T can be `ìnt` but not with the example that I show. You would have to use built-in interface `IAdditionOperators<.,.,.>` in the `System.Numerics` namespace. I advise you to look into the other classes in this namespace because there is a lot of other interesting interfaces. – nrmontagne Dec 07 '22 at 18:02
6

The Type parameter constraints in C# are very limited and is listed here. So the answer is no as far as compile time check goes. If T is a type that you create and manage, one way to go about it would be to

interface IAddable 
{
   IAddable Add(IAddable foo);
}

and implement IFoo for all your types and use where T: IAddable as constraint and use Add() instead of +

Bala R
  • 107,317
  • 23
  • 199
  • 210
3

With C# 8 default interface methods you can achieve something similar, but it might not solve your exact use case:

You can define an interface with a default implementation of an operator:

public interface IFoo
{
    double Value { get; }

    public static IFoo operator +(IFoo a, IFoo b)
    {
        return new Foo(a.Value + b.Value);
    }
}

public class Foo : IFoo
{
    public double Value { get; }

    public Foo(double value)
    {
        Value = value;
    }
}

And consume it in a generic method/class like this:

public static class Program
{
    public static void Main()
    {
        var f1 = new Foo(1);
        var f2 = new Foo(2);
        var sum = Add(f1, f2);
        Console.WriteLine(sum.Value);
    }

    public static IFoo Add<T>(T a, T b) where T : IFoo
    {
        return a + b;
    }
}
tomfroehle
  • 602
  • 5
  • 16
1

Using a generic constraints you can force T

  • to be a reference type or a value type
  • to inherit from a certain class
  • to implement certain interface
  • to have parameterless constructor

But that's all. You can't force the existence of the static operator+ on it.

svick
  • 236,525
  • 50
  • 385
  • 514