C# 当用接口隐藏类时,重写的实现是否仍然存在?

C# 当用接口隐藏类时,重写的实现是否仍然存在?,c#,selenium-webdriver,C#,Selenium Webdriver,我有IWebElement界面。它需要实现Click()方法。因此,WebDriver库中的某些方法返回实现的IWebElement 我有自己的接口IPageElement:IWebElement和一个具体的类PageElement,它实现了Click()方法不同(一些等待和异常处理) 假设我有两种方法: IPageElement GetSomething() => new PageElement(); IWebElement GetSomethingElse() => new Pa

我有
IWebElement
界面。它需要实现
Click()
方法。因此,WebDriver库中的某些方法返回实现的
IWebElement

我有自己的接口
IPageElement:IWebElement
和一个具体的类
PageElement
,它实现了
Click()方法不同(一些等待和异常处理)

假设我有两种方法:

IPageElement GetSomething() => new PageElement();
IWebElement GetSomethingElse() => new PageElement();

据我所知,结果将被削减,只保留接口成员。但是我会保留被覆盖的
Click()
PageElement
实现?

是。IPageElement的任何实现都必须同时实现Click()和GetSomething()方法,以便这些方法在IPageElement的任何结果实现中都可用。如果将相同的实现分配给IWebElement,则只有click方法可用,因为IWebElement没有定义GetSomething

public interface IWebElement
{
    void Click();
}

public interface IPageElement : IWebElement
{
    void GetSomething();
}

public class PageElementImpl : IPageElement
{
    public void Click()
    {
        Console.WriteLine("Click");
    }

    public void GetSomething()
    {
        Console.WriteLine("GetSomething");
    }
}

static void Main(string[] args)
{
    IWebElement webElement = new PageElementImpl();
    IPageElement pageElement = new PageElementImpl();

    webElement.Click();  //Legal
    pageElement.Click();  //Legal
    webElement.GetSomething();  //Not Legal as GetSomething() is not part of IWebElment
    pageElement.GetSomething();  //Legal
}
让我们编写一些代码

interface IW
{
  void C();
}
interface IP : IW
{
  void D();
}
class W : IW
{
  public virtual void C() { Console.WriteLine("WC"); }
}
class P : W, IP
{
  public override void C() { Console.WriteLine("PC"); }
  public virtual void D() { Console.WriteLine("PD"); }
}
...
IP ip = new P();
ip.C(); // PC
IW iw = new P();
ip.C(); // PC
在这两种情况下,覆盖实现都会获胜

但是,它是一个压倒一切的实现,这一点非常重要。C#中有一条非常微妙且经常被误解的规则。考虑这种情况:

class W2 : IW
{
  public void C() { Console.WriteLine("W2C"); } // NOT VIRTUAL
}
class P2 : W2, IP
{
  public new void C() { Console.WriteLine("P2C"); }
  public virtual void D() { Console.WriteLine("P2D"); }
}
这里发生了什么

IP ip = new P2();
ip.C();
IW iw = new P2();
ip.C();
同样,我们两次都得到P2C。所以一切看起来都很好,即使“覆盖”是非虚拟化的过载,对吗

那么当我们这样做的时候会发生什么呢

class P3 : P2
{
  public new void C() { Console.WriteLine("P3C"); }
}
...
IP ip = new P3();
ip.C();
IW iw = new P3();
ip.C();
我们两次仍然得到P2C。这可能令人惊讶!非虚拟重写重载方法不会更新此处的接口实现,但在上一个示例中更新了!为什么呢

如果您这样做:

class P4 : P2, IP // NOTE IP
{
  public new void C() { Console.WriteLine("P4C"); }
}
...
IP ip = new P4();
ip.C();
IW iw = new P4();
ip.C();
然后我们打印出P4C

C#中的规则是,当继承列表中提到接口时,编译器决定哪个方法槽与哪个接口成员相关联。这是P3和P4之间唯一密切相关的区别


这在C#中被称为“接口重新实现规则”,这相当棘手。如果要将非虚拟方法与接口重新实现和继承混合使用,请务必小心。

当您尝试对从
GetSomething
GetSomethingElse
返回的任何对象运行click方法时,会发生什么情况?接口没有实现,因此PageElement中的非实现将“覆盖”任何现有的logic@ChetanRanpariya,它可能会以某种方式点击它。由于检查实现需要一个异常,而且我在测试项目中没有可以轻松使用的控制台来附加
控制台。WriteLine
测试实际使用的实现并不是那么简单。您确实有一个浏览器,所以可以在这里尝试。创建一些类和接口,看看会发生什么。这比在上面发布原始问题要省力。试试Igor的建议。这会消除你的疑虑。即使在那之后,你有任何困惑,欢迎回到这里。