0

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.

ph3rin
  • 4,426
  • 1
  • 18
  • 42
  • In C#, there is no language-level mechanism to prevent this kind of issue with default interface methods. However, starting from C# 8.0, you can use the "default" keyword in the implementation to explicitly call the default implementation from the interface. For example, in the code you provided, you could change ExampleImplementation's implementation of Foo to: ---public int Foo(int additional_argument) => default + additional_argument + 42;--- This would ensure that ExampleImplementation is correctly implementing the default interface implementation, and calling it as expected. – Tony Feb 14 '23 at 03:36
  • Another way is to use unit tests that assert the expected behavior of the implementing class, ensuring that it adheres to the contract of the interface. – Tony Feb 14 '23 at 03:37
  • In C#, there is no language feature similar to C++'s override keyword that enforces method implementation to properly override an interface's default implementation. Therefore, it's the programmer's responsibility to ensure that the method implementation matches the signature of the interface's default implementation. – Tony Feb 14 '23 at 03:37

2 Answers2

2

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;
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
0

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.

AlphaModder
  • 3,266
  • 2
  • 28
  • 44