【问题标题】:Override method implementation declared in an interface覆盖接口中声明的方法实现
【发布时间】:2012-09-01 03:40:57
【问题描述】:

我有一个接口,里面有几个方法。

interface IMyInterface
{
    //...
    void OnItemClicked()
    //...
}

还有一个实现

class MyClass : IMyInterface
{
    //Other methods
    public void OnItemClicked(){ /*...*/ } 
}

现在,我想要一个行为类似于 MyClass 的类,除了 OnItemClicked(),我想要对这个方法进行一些修改。

我想继承一个覆盖,但我不想更改MyClass(例如:public virtual void OnItemClicked()...),因为它不是我的实现,

我不想再次实现IMyInterface,因为 OnItemClicked() 是 MyClass 中唯一需要修改的部分。

我还有其他方法吗?

【问题讨论】:

  • 在这两者之间创建一个中间类。

标签: c# inheritance interface


【解决方案1】:

由于您正在实现一个接口,多态性可能是您想要保留的东西。如果不使用 virtual 修改基类,就不可能覆盖该方法,因此您必须像 Tigran 所写的那样使用 new 而不是 virtual。

这意味着编写这种代码但只执行方法的基本版本:

List<MyClass> aList = new List<MyClass>();
aList.Add(new MyClass());
aList.Add(new MyNewClass());
foreach (MyClass anItem in aList)
    anItem.OnItemClicked();

要执行正确的代码,您应该编写如下丑陋的代码:

List<MyClass> aList = new List<MyClass>();
aList.Add(new MyClass());
aList.Add(new MyNewClass());
foreach (MyClass anItem in aList)
{
    MyNewClass castItem = anItem as MyNewClass;
    if (castItem != null)
        castItem.OnItemClicked();
    else
        anItem.OnItemClicked();
}

无论如何,有一种方法可以让您的类在分配给声明为 IMyInterface 的变量时执行正确的方法。要走的路是显式实现要覆盖的接口部分,在您的情况下是 OnItemClicked 方法。代码如下:

public class MyNewClass : MyClass, IMyInterface // you MUST explicitly say that your class implements the interface, even if it's derived from MyClass
{
    public new void OnItemClicked() //NEW keyword here you have the overridden stuff
    { 
        /*...*/ 
    } 

    void IMyInterface.OnItemClicked() // No need for public here (all interfaces's methods must be public)
    { 
        this.OnItemClicked(); 
    } 
}

这样:

 MyClass cl = new MyNewClass(); 
 cl.OnItemClicked();

执行基本方法

 MyNewClass cl = new MyNewClass(); 
 cl.OnItemClicked();

执行派生类的方法

 IMyInterface cl = new MyNewClass(); 
 cl.OnItemClicked();

执行派生类的方法并在运行时绑定。这意味着您可以像这样编写我最初示例的代码并执行正确的方法:

List<IMyInterface> aList = new List<IMyInterface>();
aList.Add(new MyClass());
aList.Add(new MyNewClass());
foreach (IMyInterface anItem in aList)
    anItem.OnItemClicked();

【讨论】:

    【解决方案2】:

    你可以派生自MyClass

    public class MyNewClass : MyClass
    {
        public new void OnItemClicked(){ /*...*/ } //NEW keyword
    }
    

    唯一要注意的是,这种方式不支持多态性。

    为了更清楚:

         MyClass cl = new MyNewClass(); 
         cl. MyMethod();
    

    这将调用MyClass 方法,即使real 对象类型是MyNewType。 为了能够调用我们想要的,我们必须明确定义类型

         MyNewClass cl = new MyNewClass(); 
         cl. MyMethod(); //WILL CALL METHOD WE WANT
    

    【讨论】:

    • 他在帖子中提到:我想继承一个覆盖,但我不想更改 MyClass(如:public virtual void OnItemClicked()...),因为它不是我的实现,
    • @armen.shimoon:事实上他没有。您在哪里看到更改 MyClass 实现的代码?
    • 我的坏蒂格兰。我浏览了代码,并认为您使用的是“覆盖”而不是“新”。问:当MyNewClass作为“IMyInterface”的实例时,会调用哪个方法?
    • @armen.shimoon:看看我的帖子示例。此功能不支持多态性。
    • 我想接口是多态的。说得通。我想这取决于他现在的使用情况。
    【解决方案3】:

    最简单的方法是使用“has-a”创建一个模仿“is-a”的新类:

    public interface IMyInterface
    {
        void OnItemClicked();
        void OnItemHover();
        void OnItemDoubleClicked();
    }
    
    public class MyNewClass : IMyInterface
    {
        private IMyInterface _target;
    
        public MyNewClass(IMyInterface target)
        {
            _target = target;
        }
    
        public void OnItemClicked()
        {
            // custom functionality
        }
    
        public void OnItemHover()
        {
            _target.OnItemHover();
        }
    
        public void OnItemDoubleClicked()
        {
            _target.OnItemDoubleClicked();
        }
    }
    

    【讨论】:

    • 好的,但你不能将它分配给 MyClass 变量
    • 是的,但是在您可以将其分配给 MyClass 变量并且您调用 OnItemClicked() 的答案中,它会执行错误的函数。我假设界面是重要的部分,否则这将无法正常工作,但其他答案也不会。
    • 你说得对,事实上,我更喜欢你的答案,我只是指出为什么我更喜欢我的答案 :-)
    【解决方案4】:

    【讨论】:

    • 链接消失。请保留这种答案作为cmets,请
    猜你喜欢
    • 1970-01-01
    • 2011-08-04
    • 2022-01-01
    • 1970-01-01
    • 2015-04-29
    • 2014-11-20
    • 1970-01-01
    • 1970-01-01
    • 2013-09-23
    相关资源
    最近更新 更多