C# 8中的默认接口方法

10

考虑以下代码示例:

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
{
}

使用代码:

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

我的问题在于这段代码:

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

问题是:输出应该是15还是55?!
根据.NET团队: 决定:2017-04-11做出:运行I2.M,在运行时这是最具体的重载。 因为覆盖接口上有关键字“new”,我不确定这里应该怎么做才是正确的行为?
如果您需要从源代码进行编译,可以从以下位置下载源代码: https://github.com/alugili/Default-Interface-Methods-CSharp-8

我可以编译代码,但无法执行它!为什么无法执行?在我看来,输出应该是55 - Camilo Terevinto
1
我认为这与IPowerPlayerAttack方法显式实现了IPlayer方法有关,而ILimitedPlayerAttack方法是隐式实现的。或者可能是因为它使用了new关键字来隐藏它。这可能是两者的结合体。 - Zohar Peled
@BassamAlugili 这有点混乱。我觉得不应该允许你在每个接口上拥有两个同名但不同功能的方法,这样编译也不应该通过。 - Michael Puckett II
2
也许你应该等待 C#8 编译器? - stuartd
@Michael Puckett II,请查看代码并从该分支开始启动,它将编译无任何问题! - Bassam Alugili
显示剩余6条评论
2个回答

7
是的,这是因为new关键字实际上隐藏了派生类型的实现,就像对于类也是完全相同的行为,我们称之为Shadowing concept
所以输出将是55,因为您对Player对象有IPlayer类型的引用,并且由于new关键字在其签名中,ILimitedPlayerAttack方法被隐藏在IPlayer之外。

@CamiloTerevinto 很抱歉,我再次澄清了一些细节。 - Ehsan Sajjad
我不完全确定这是否是正确的答案。请阅读原帖中的评论:“除了执行,我还遇到了一个错误-->接口中不允许使用方法”。 - Camilo Terevinto
@CamiloTerevinto C#以前不支持接口中的任何可见性属性,比如public private,所以我对C# 8还不是很熟悉。但是如果上面的代码能够编译通过,那么看起来现在我们可以定义了。 - Ehsan Sajjad
1
我觉得很惊讶我们正在讨论一个甚至还没有决定的功能(该存储库仍然称拥有“new”为开放问题),而且我甚至不确定这段代码是否编译。 - DavidG
@DavidG,这是由于阴影效应的工作原理造成的,我们目前不希望在面向对象编程的新版本中出现任何破坏性变化。 - Ehsan Sajjad
显示剩余10条评论

3

我认为即使没有C#8编译器,你也可以对这个工作原理有一个“良好的猜测”。我们在这里基本上有:

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);
}

我们有两种接口方法(具有相同的签名),以及一些接口(IPowerPlayerILimitedPlayer)提供这些方法的实现。我们可以在Player类本身中提供实现来实现类似的功能:

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

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

然后运行问题中的代码,输出结果如下:

55

55

15

我认为这个结果相对比较明显。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接