【问题标题】:Using interfaces on abstract classes in C#在 C# 中的抽象类上使用接口
【发布时间】:2010-10-15 14:48:54
【问题描述】:

我正在从 C++ 学习 C#,但遇到了障碍。

我有一个抽象类 AbstractWidget、一个接口 IDoesCoolThings 和一个派生自 AbstractWidget 的类 RealWidget:

public interface IDoesCoolThings
{
    void DoCool();
}

public abstract class AbstractWidget : IDoesCoolThings
{
    void IDoesCoolThings.DoCool()
    {
        Console.Write("I did something cool.");
    }
}

public class RealWidget : AbstractWidget
{

}

当我实例化一个 RealWidget 对象并对其调用 DoCool() 时,编译器给我一个错误提示

'RealWidget' 不包含 'DoCool' 的定义

我可以将 RealWidget 对象转换为 IDoesCoolThings,然后调用将起作用,但这似乎没有必要,而且我也失去了多态性(即使我定义了 RealWidget.DoCool(),AbstractWidget.DoCool() 也将始终被调用)。

我认为解决方案很简单,但我尝试了很多方法,但终生无法解决这个问题。

【问题讨论】:

  • 要在小部件的 DoCool() 中具有多态性,您需要声明 AbstractWidget 的一个虚拟部件。
  • 尔格。我在某处读到了接口方法隐含的 virtual。

标签: c# inheritance interface abstract-class


【解决方案1】:

您遇到问题是因为您使用了 explicit interface implementation (EII)。当一个成员被显式实现时,它不能通过类实例访问——只能通过接口的实例。在您的示例中,这就是您不能调用 DoCool() 的原因,除非您将实例转换为 IDoesCoolThings

解决办法是把DoCool()设为public,去掉显式接口实现:

public abstract class AbstractWidget : IDoesCoolThings
{
    public void DoCool()      // DoCool() is part of the abstract class implementation.
    {
        Console.Write("I did something cool.");
    }
}

// ...

var rw = new RealWidget();
rw.DoCool();                  // Works!

一般来说,您在两种情况下使用 EII:

  • 您有一个必须实现两个接口的类,每个接口都包含一个成员,该成员与另一个接口中的另一个成员具有相同的名称/签名。
  • 您希望强制客户端不依赖于您的类的实现细节,而是依赖于您的类正在实现的接口。 (有些人认为这是一种很好的做法。)

【讨论】:

  • 天哪,我以为我试过了。谢谢!我似乎错过了我的参考书中的这一关键行:“使用显式接口实现定义的方法不能声明为虚拟,而省略接口名称允许这种行为。”
  • 我很困惑,简单地在抽象类中公开方法并不能解决问题,加上我阅读的示例没有将方法定义为公共或私有,所以我开始相信接口方法是隐含的公共和虚拟的。总的来说,一个令人尴尬的问题:)。不过谢谢!
  • 如果派生类的成员覆盖可能希望返回从基类的实现派生的类型,则显式接口实现也可能很好。例如,CarFactoryICarFactory 可能都有返回 CarMakeCar() 方法,但 FordCarFactory 可能希望有一个 MakeCar() 方法返回 FordCar。这通常可以通过使用返回 Carprotected 虚拟 DoMakeCar 方法并同时拥有 ICarFactory.MakeCar 和非虚拟 CarFactory.MakeCar 方法链来处理。
【解决方案2】:

将您的声明更改为:

public abstract class AbstractWidget : IDoesCoolThings 
{
    public void DoCool()
    { 
        Console.Write("I did something cool."); 
    }
}

【讨论】:

    【解决方案3】:

    如果选择隐式实现接口,则实现接口的方式是显式实现 void IDoesCoolThings.DoCool()。

    public abstract class AbstractWidget : IDoesCoolThings
    {
        public void DoCool()
        {
            Console.Write("I did something cool.");
        }
    }
    

    然后就可以了。

    阅读:

    C# Interfaces. Implicit implementation versus Explicit implementation

    【讨论】:

    • 感谢您将链接添加到关于隐式和显式实现的 SO 问题!
    【解决方案4】:

    你应该这样做:

    public interface IDoesCoolThings 
    {
       void DoCool();
    }
    
    public abstract class AbstractWidget 
    {
       public void DoCool()
       {
          Console.WriteLine("I did something cool.");
       }
    }
    
    public class Widget : AbstractWidget, IDoesCoolThings 
    {
    }
    

    用法:

    var widget = new Widget();
    widget.DoCool();
    

    【讨论】:

      猜你喜欢
      • 2015-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-12
      • 2021-04-14
      • 2013-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多