在c#中实现多态性,如何最好地实现它?

在c#中实现多态性,如何最好地实现它?,c#,oop,polymorphism,C#,Oop,Polymorphism,第一个问题,希望你们都对我温柔一点 在过去的几天里,我读了很多关于多态性的书,并试图将其应用到我在c#中所做的工作中,似乎有几种不同的方法来实现它。我希望我已经掌握了这一点,但我会很高兴,即使我没有澄清 据我所见,我有3种选择: 我可以从一个基地继承 类并使用关键字 “virtual”在我 希望我的派生类 覆盖 我可以用虚拟方法实现一个抽象类 这样做 我可以使用界面吗 从我所看到的,如果我不需要在基类中使用任何实现逻辑,那么接口就给了我最大的灵活性(因为我不会在多重继承等方面限制自己),但是如果

第一个问题,希望你们都对我温柔一点

在过去的几天里,我读了很多关于多态性的书,并试图将其应用到我在c#中所做的工作中,似乎有几种不同的方法来实现它。我希望我已经掌握了这一点,但我会很高兴,即使我没有澄清

据我所见,我有3种选择:

  • 我可以从一个基地继承 类并使用关键字 “
    virtual
    ”在我 希望我的派生类 覆盖
  • 我可以用虚拟方法实现一个抽象类 这样做
  • 我可以使用界面吗
  • 从我所看到的,如果我不需要在基类中使用任何实现逻辑,那么接口就给了我最大的灵活性(因为我不会在多重继承等方面限制自己),但是如果我需要基类能够在派生类所做的任何事情之上做一些事情,那么使用1或2将是更好的解决方案

    感谢大家对我的意见-我这个周末在这个网站和其他地方读了很多,我想我现在理解了这些方法,但是我只想用一种特定于语言的方式澄清一下我是否走上了正确的道路。希望我已经正确地标记了这个

    干杯,
    特里

    以上三项都是有效的,并且都有其自身的用处。 没有“最好”的技术。只有编程实践和经验才能帮助您在正确的时间选择正确的技术

    因此,现在选择一种似乎合适的方法,并立即实施。
    观察哪些有效,哪些失败,吸取教训,然后再试一次。

    界面提供了最抽象的概念;您没有绑定到任何特定的实现(如果由于其他原因,实现必须具有不同的基类,那么这将非常有用)

    对于真正的多态性,
    virtual
    是必须的;多态性最常见于类型子类化

    当然,您可以将两者混合使用:

    public interface IFoo {
        void Bar();
    }
    class Foo : IFoo {
        public virtual void Bar() {...}
    }
    class Foo2 : Foo {
        public override ...
    } 
    
    摘要
    是一个单独的问题;
    abstract
    的选择实际上是:它能被基类合理地定义吗?如果没有默认实现,则它必须是
    抽象的

    当存在许多公共的实现细节时,公共基类是有用的,并且纯粹通过接口复制是没有意义的;但有趣的是,如果每个实现的实现都不会不同,那么扩展方法提供了一种有用的方法,可以在
    接口上公开这一点(这样每个实现就不必这样做):


    由于以下几个原因,接口通常受到青睐:

    • 多态性是关于契约的,继承是关于重用的
    • 继承链很难获得正确的结果(特别是对于单个继承,请参见Windows窗体控件中的设计错误,其中滚动性、富文本等功能在继承链中硬编码)
    • 继承会导致维护问题
    也就是说,如果您想利用公共功能性,可以使用接口进行多态性(让您的方法接受接口),但可以使用抽象基类来共享一些行为

    public interface IFoo
    {
        void Bar();
        enter code here
    }
    
    将是您的界面

    public abstract class BaseFoo : IFoo
    {
        void Bar
      {
            // Default implementation
      }
    }
    
    将是您的默认实现

    public class SomeFoo : BaseFoo
    {
    
    }
    
    是一个重用实现的类

    不过,您将使用接口实现多态性:

    public class Bar
    {
       int DoSometingWithFoo(IFoo foo)
    {
    
        foo.Bar();
    }
    }
    

    请注意,我们在方法中使用了接口。

    您应该问的第一件事是“为什么我需要使用多态性?”,因为多态性本身并不是一个目的,而是达到目的的一种手段。一旦您清楚地定义了问题,应该更清楚地使用哪种方法

    无论如何,您评论的这三种方法不是独占的,如果您需要在某些类之间重用逻辑,而不是在其他类之间重用逻辑,或者需要一些不同的接口,您仍然可以将它们混合使用…

    • 使用抽象类强制类结构
    • 使用接口描述行为

    这实际上取决于您想要如何构造代码以及您想要用它做什么

    从测试的角度来看,拥有接口类型的基类是很好的,因为您可以使用模拟对象来替换它

    如果您希望在某些函数中而不是在其他函数中实现代码,那么抽象类实际上就是抽象类,就好像抽象类只有抽象函数一样,它实际上是一个接口

    请记住,抽象类不能实例化,因此对于工作代码,必须有一个派生自它的类

    实际上,所有这些都是有效的

    我倾向于使用抽象类,如果我有很多类是从抽象类派生出来的,但是这些类的层次很浅(比如说只有一个类)

    如果我期望有一个深层次的继承,那么我就使用一个带有虚拟函数的类


    因此,最好保持类的简单性,以及它们的继承性,因为它们越复杂,就越有可能引入bug。

    绝对-我想上面提到的并不是为了使用多态性,而是为了更好地理解方法,以及何时使用每种方法(或者如你所说,混合匹配以适应)我喜欢以这种方式使用extenson方法来创建重载。这样我的接口很容易实现,所有实现都以同样的方式处理重载。我真的很喜欢这个解释,Marc,你和下面的Yann都花了很多精力来解释答案,谢谢你-显然会等着看还有什么是的,但是谢谢-这真的很有帮助!@Jacob-的确;它对于可选参数非常有用(直到我们得到C#4.0)-例如,我倾向于在接口上使用查询方法的“分页”版本,并使用扩展方法提供默认的“get everything”(更简单)重载-然后我只有1个方法在具体站点上实现,而不是2个
    public class Bar
    {
       int DoSometingWithFoo(IFoo foo)
    {
    
        foo.Bar();
    }
    }