Default Interface Methods in C# 8
Asked Answered
N

2

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

Neologism answered 16/4, 2018 at 15:12 Comment(11)
"I can compile the code but not execute it!" why cannot you execute it? IMO, output would be 55Abridge
I think it has to do with the fact that the IPowerPlayer Attack method is explicitly implementing the IPlayer method, while the ILimitedPlayer Attack method is implicitly implementing it. Or maybe it's because it shadows it with the new keyword. It's probably a combination of both.Goebel
@BassamAlugili This is messed up. I don't feel like it should compile allowing you to have two methods, same name, different functions, on each interface like that.Breakfast
@CamiloTerevinto executing does not work I have build the branch and started the feature .everything working fine, compiling, intelli etc. except the executing im getting an error --> Methods does not allowed in the interfacesNeologism
@BassamAlugili So isn't the answer that the output would be a runtime exception rather than 15 or 55?Abridge
Perhaps you should wait for a C#8 compiler?Jepum
@Michael Puckett II just check out the code and start it from the branch it will be compile without any problem!Neologism
I understand it compiles and I understand the new keyword being used but it's a mess.Breakfast
@CamiloTerevinto why? do you have a references for that? I believe 15Neologism
I would wait until Visual Studio preview gets support for c# 8 (currently it supports 7.3). You might have hit an unresolved bugAbridge
In java what we shall get? any java developer here?Neologism
M
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

Matherne answered 16/4, 2018 at 15:16 Comment(15)
@CamiloTerevinto sorry about that, clarified moreMatherne
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"Abridge
@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 defineMatherne
@MichaelPuckettII You really didn't understand my comment. I am familiar with what's being done, and the OP posted the runtime exception, not meAbridge
this is exactly my first idea but if you thinking deeply, the most specific override at runtime is in the ILimitedPlayer because? correct?!Neologism
this might be of help too : github.com/dotnet/csharplang/issues/288Matherne
@BassamAlugili Not really, because that's not an override, it's shadowingAbridge
yes, @CamiloTerevinto is right, instead of override it's new keywordMatherne
@CamiloTerevinto aha perfect! thank you! so why you think it should throw an exception and not hiding the "shadowing"Neologism
@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 runAbridge
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) and I'm not even sure this code compiles.Cordie
thank you all for help! @EhsanSajjad i will leave it as open for a while.Neologism
@Cordie That's what I meant by my last commentAbridge
@CamiloTerevinto Indeed, but Ehsan is convinced the output is 55, I would like to know where that surety comes from.Cordie
@Cordie 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 versionMatherne
I
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.

Irreplaceable answered 16/4, 2018 at 16:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.