Making sure a C# method matches the signature of an interface default implementation

131 views Asked by At

Consider the following C# example:

using System;

interface IExample
{
   public int Foo() => 42;
}

class ExampleImplementation : IExample
{
   public int Foo() => 37;
}

class Program
{
   static void Main(string[] args)
   {
       IExample example = new ExampleImplementation();
       Console.WriteLine($"{example.Foo()}");
   }
}

The code will output 37 as expected.

However, if I change the method signature in the interface, but NOT that of the implementation, like this:

interface IExample
{
   int Foo(int additional_argument) => additional_argument + 42;
}

class ExampleImplementation : IExample
{
   int Foo() => 37;
}

class Program
{
   static void Main(string[] args)
   {
       IExample example = new ExampleImplementation();
       Console.WriteLine($"{example.Foo(0)}");
   }
}

The program will output 42 instead.

Now this is undesired behavior, because the method Foo in ExampleImplementation is written to implement (and override) the default implementation, but in the new code it fails to do so.

There are ways to mitigate this, such as using an IDE that allows you to change the signature of methods along the chain. However, I wish to know whether is anything at the language level that can prevent this.

As a side note, in C++, the override keyword is used for exactly this purpose: to make sure a member function is actually overriding something from the base. If I were using an abstract class, then I can do something similar, but I want to know if there is something similar to default interface implementations.

2

There are 2 answers

0
Sweeper On BEST ANSWER

Explicit interface implementations in C# are required to match the signatures of the method they are implementing, so you could do:

class ExampleImplementation : IExample
{
   int IExample.Foo() => 37;
   
   public int Foo() => ((IExample)this).Foo();
}

The public method is added so that you can still call Foo on something of type ExampleImplementation.

Alternatively, you can do it "the other way round":

class ExampleImplementation : IExample
{
   int IExample.Foo() => Foo();
   
   public int Foo() => 37;
}
0
AlphaModder On

This could be a usecase for explicit interface implementation. If you write your implementation as:

class ExampleImplementation : IExample
{
   int IExample.Foo() => 37;
}

And then change the signature of Foo in IExample, the above code will no longer compile.

However, this will also make it impossible to call the Foo implementation on an ExampleImplementation without first casting to IExample. That is, this will still work:

IExample example = new ExampleImplementation();
Console.WriteLine($"{example.Foo(0)}");

But this won't:

ExampleImplementation example = new ExampleImplementation();
Console.WriteLine($"{example.Foo(0)}");

Depending on the particulars of your situation, that may or may not be a problem.