10

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

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
Bassam Alugili
  • 16,345
  • 7
  • 52
  • 70

2 Answers2

7

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

ken2k
  • 48,145
  • 10
  • 116
  • 176
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
  • @CamiloTerevinto sorry about that, clarified more – Ehsan Sajjad Apr 16 '18 at 15:20
  • I am not completely sure this is the correct answer though. Read the comment from the OP: "except the executing im getting an error --> Methods does not allowed in the interfaces" – Camilo Terevinto Apr 16 '18 at 15:20
  • @CamiloTerevinto C# used to not support any visibility attributes like public private in interface, so i am not much familiar yet with C# 8 but if above code compiles of OP then looks like now we can define – Ehsan Sajjad Apr 16 '18 at 15:24
  • @MichaelPuckettII You really didn't understand my comment. I am familiar with what's being done, and the OP posted the runtime exception, not me – Camilo Terevinto Apr 16 '18 at 15:24
  • this is exactly my first idea but if you thinking deeply, the most specific override at runtime is in the ILimitedPlayer because? correct?! – Bassam Alugili Apr 16 '18 at 15:26
  • this might be of help too : https://github.com/dotnet/csharplang/issues/288 – Ehsan Sajjad Apr 16 '18 at 15:26
  • @BassamAlugili Not really, because that's not an override, it's shadowing – Camilo Terevinto Apr 16 '18 at 15:26
  • yes, @CamiloTerevinto is right, instead of `override` it's `new` keyword – Ehsan Sajjad Apr 16 '18 at 15:27
  • @CamiloTerevinto aha perfect! thank you! so why you think it should throw an exception and not hiding the "shadowing" – Bassam Alugili Apr 16 '18 at 15:28
  • @BassamAlugili I don't think it should throw an exception, I was just mentioning the output you got when you ran that. It *might* be that the team hasn't tackled that feature yet, or it *could* be that there's no way to determine which method should run – Camilo Terevinto Apr 16 '18 at 15:29
  • 1
    I find it surprising that we're discussing a feature that hasn't even been decided on yet (the repo still calls having `new` an [open issue](https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md)) and I'm not even sure this code compiles. – DavidG Apr 16 '18 at 15:29
  • thank you all for help! @EhsanSajjad i will leave it as open for a while. – Bassam Alugili Apr 16 '18 at 15:31
  • @DavidG That's what I meant by my last comment – Camilo Terevinto Apr 16 '18 at 15:31
  • @CamiloTerevinto Indeed, but Ehsan is convinced the output is 55, I would like to know where that surety comes from. – DavidG Apr 16 '18 at 15:32
  • @DavidG the comes from how shadowing works and we are not expecting any breaking change uptil now for how OOP works in general in the newer version – Ehsan Sajjad Apr 16 '18 at 15:34
3

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.

Evk
  • 98,527
  • 8
  • 141
  • 191