51

Can anyone please explain why C# interfaces are not allowed to contain operators?

Thanks.

dkackman
  • 15,179
  • 13
  • 69
  • 123
Jake
  • 16,329
  • 50
  • 126
  • 202

3 Answers3

71

C# operators have to be static. Interfaces, by definition, apply to instances. There is no mechanism to require a type to implement static members.

EDIT:
Since C# 8.0, as you can see here, it is now possible to define local methods in interfaces and implement them within the interface itself, e.g. allowing to create method overloads without requiring implementations to care about those overloads as well, when they might just supply an additional parameter to the overload that has to be implemented.
Along with this, you can also define operators within interfaces, though they must be static and so they must be implemented in the interface.

So in C# 8.0 this will print "this works in C# 8" followed by "1":

interface ICanAdd
{
    int Value { get; }

    public static int operator+ (ICanAdd lvalue, int rvalue)
    {
        Console.WriteLine("this works in C# 8");
        return lvalue.Value + rvalue;
    }
}

class Add : ICanAdd
{
    public int Value => 0;
}

class Program
{
    static void Main(string[] args)
    {
        ICanAdd foo = new Add();
        var x = foo + 1;
        Console.WriteLine(x);
    }
}

Edit 2020-01-23

You cannot add conversion, equality or inequality operators to interfaces, otherwise you'll hit the following error:

CS0567 C# Interfaces cannot contain conversion, equality, or inequality operators

Yennefer
  • 5,704
  • 7
  • 31
  • 44
dkackman
  • 15,179
  • 13
  • 69
  • 123
  • Extension methods come to mind, but extension methods can't be used as operators or properties. – Jeffrey Hantin Jul 06 '11 at 22:49
  • But is there a reason that interfaces couldn't be enhanced to include static methods and operators? – cordialgerm Jul 07 '11 at 00:05
  • 3
    @pickles - there is no hard and fast reason why a language/compiler couldn't create such a construct (I think that there may actually be some out there that do - Delphi maybe, and it can be mimicked somewhat (static virtual methods at least) in C++ using templates (T::Method())) - C# chose not to. – dkackman Jul 07 '11 at 00:30
  • 2
    The second answer to this post has some commentary as to why C# does not have this. http://stackoverflow.com/questions/259026/why-doesnt-c-allow-static-methods-to-implement-an-interface – dkackman Jul 07 '11 at 00:36
  • 7
    Sorry to revive an old thread, but since the indexing bracket operator/"property" is not static, they can be used in an interface. – Greg Kramida Apr 17 '12 at 17:04
  • 4
    @GregKramida The difference in C# is that an indexer isn't technically an operator as it is in C++. It's syntactic sugar in the language that bakes down to an instance method get_Item in IL. In the grammar spec indexers and operators are declared separately and differently. https://msdn.microsoft.com/en-us/library/aa664812(v=vs.71).aspx – dkackman Aug 25 '15 at 23:11
  • 2
    Thanks to @DavideCannizzo for pointing out that this changed in C# 8 – dkackman Dec 23 '19 at 18:42
  • 1
    Does anyone know why the restriction on equality operators exists? – Mike Marynowski Jul 28 '20 at 04:45
3

You can't define operators on interfaces because a class can implement multiple interfaces. Imagine if this code were possible:

static class Fooness {
  public static operator==(IFoo l, IFoo r) { ... }
}
static class Barness {
  public static operator==(IBar l, IBar r) { ... }
}

public class Foobar : IFoo, IBar { ... }

Which == implementation should prevail if used on instances of Foobar? (And before you answer, imagine if IFoo/Fooness come from one DLL and IBar/Barness comes from another).

Even if you could somehow resolve that ambiguity, we should ask ourselves whether it would even be a good idea. I hope the above shows that with operator== it's a seriously bad idea. The author of the per-interface == operator presumes that the only important aspects of an object when it comes to comparison are those encompassed by the interface. Sometimes that can be true, but it's not generally true.

That's why it's prudent to only use operators on sealed classes. Only then can you be sure that your operator knows enough about the object to work correctly.

Steve Benz
  • 298
  • 2
  • 8
  • the priority of conflicting implementations should be in the order that they are declared on the class that inherits them, ie with `public class Foobar : IFoo, IBar` if both `IFoo` and `IBar` call for an implementation of == then `IFoo` should take priority since it is declared first. An example of where having == be implemented directly inside the interface would be a good idea is with the `IEquatable` interface where it would call `.Equals` which the user implements anyways, it would simply ensure that any IEquatable would always allow a developer to call `==` and `!=` on it. –  Feb 28 '22 at 02:27
  • 1
    @RWolfe why the first instead of the last? – Kirill Aug 04 '22 at 02:14
2

If your method could not be properly implemented on the interface, you can make a call to a self method that will be overriden by the derived class:

public interface INotification
{
        INotification Combine(INotification b);
        
        public static INotification operator +(INotification a, INotification b)
        {
            return a.Combine(b);
        }
}

Derived class:

public class Notification : INotification
{

        public INotification Combine(INotification b)
        {
            _events.AddRange(b.Events);
            _logs.AddRange(b.Logs);
            ValidationResult.Errors.AddRange(b.GetValidationErrors());

            return this;
        }

        public static Notification operator +(Notification a, Notification b)
        {
            a._events.AddRange(b.Events);
            a._logs.AddRange(b.Logs);
            a.ValidationResult += b.ValidationResult;

            return a;
        }
}