Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default Interface Methods in C# 8

Consider the following code example:

public interface IPlayer
{
  int Attack(int amount);
}

public interface IPowerPlayer: IPlayer
{
  int IPlayer.Attack(int amount)
  {
    return amount + 50;
  }
}

public interface ILimitedPlayer: IPlayer
{
  new int Attack(int amount)
  {
    return amount + 10;
  }
}

public class Player : IPowerPlayer, ILimitedPlayer
{
}

Using the code:

IPlayer player = new Player();
Console.WriteLine(player.Attack(5)); // Output 55, --> im not sure from this output. I can compile the code but not execute it!

IPowerPlayer powerPlayer = new Player();
Console.WriteLine(powerPlayer.Attack(5)); // Output 55

ILimitedPlayer limitedPlayer = new Player();
Console.WriteLine(limitedPlayer.Attack(5)); // Output 15

My problem is on the code:

Console.WriteLine(player.Attack(5)); // Output 55

The question is: The output should be 15 or 55?!

According to the .NET Team:

Decision: Made 2017-04-11: Runs I2.M, which is the unambiguously most specific override at runtime.

I'm not sure here beacuse of the keyword 'new' on the overridden interface?what should be the correct behaviour?

In case you need to compile it from source, you can download the source code from: https://github.com/alugili/Default-Interface-Methods-CSharp-8

like image 552
Bassam Alugili Avatar asked Apr 16 '18 15:04

Bassam Alugili


2 Answers

Yes, it is because of the new keyword which actually hides the derived type implementation from parent type as it was exactly the same behavior before too for classes as well which we call Shadowing concept.

So the output would be 55 as you have reference of type IPlayer for Player object and ILimitedPlayer's Attack method is hidden from IPlayer because of the new keyword in it's signatures

like image 145
Ehsan Sajjad Avatar answered Oct 04 '22 00:10

Ehsan Sajjad


I'd say you can get a "good guess" for how this should work without C#8 compiler. What we have here is basically:

public interface IPlayer {
    // method 1
    int Attack(int amount);
}

public interface IPowerPlayer : IPlayer {
    // no methods, only provides implementation
}

public interface ILimitedPlayer : IPlayer {
    // method 2, in question also provides implementation
    new int Attack(int amount);
}

So we have 2 interface methods (with same signature), and some interfaces (IPowerPlayer and ILimitedPlayer) provide implementations of those methods. We can just provide implementaitions in Player class itself to achieve similar functionality:

public class Player : IPowerPlayer, ILimitedPlayer {
    int IPlayer.Attack(int amount) {
        return amount + 50;
    }

    int ILimitedPlayer.Attack(int amount) {
        return amount + 10;
    }
}

Then running code from question outputs:

55

55

15

And I think it's relatively clear why.

like image 35
Evk Avatar answered Oct 04 '22 00:10

Evk