【问题标题】:How to achieve polymorphism in C#如何在 C# 中实现多态性
【发布时间】:2014-12-03 21:42:59
【问题描述】:

我是 C# 新手。我试图检查如何在 C# 中实现多态性,但我很困惑哪一种方法是实现多态性。我正在使用下面给出的代码,输出是A的方法。

class A
{    
    public void Display()
    {
        Console.WriteLine("A's Method");
    }
}
class B : A
{
    public void Display()
    {
        Console.WriteLine("B's Method");
    }
}

class Polymorphism
{
    public static void Main(string[] args)
    {
        A a = new B();
        a.Display();
        Console.ReadKey();
    }
}


但是当我定义如下所示的 Display() 方法时,就会调用 B 的输出方法。

class A
{    
    public virtual void Display()
    {
        Console.WriteLine("A's Method");
    }
}
class B : A
{
    public override void Display()
    {
        Console.WriteLine("B's Method");
    }
}

那么,我通过什么方式实现多态性,这两种方式之间有什么区别,哪一种方式更适合覆盖。任何帮助都将不胜感激。

【问题讨论】:

标签: c# .net


【解决方案1】:

虚拟方法提供多态性,因为子类可以覆盖行为。如果你不使用虚方法,你所拥有的只是继承了其他类型中定义的类型,但不能用新的行为替换这些继承的行为。

在第一种情况下,A 的方法被调用,因为您有一个对 A 的引用,并且非虚拟方法在编译时被解析。允许A 变量引用B 对象,因为B is-a A。 (请注意,向下转换对象并调用结果将调用B 的方法:((B)a).Display();。)

在第二种情况下,B 的方法被调用,因为该方法是虚拟的,而虚拟方法在运行时解析,基于 实际 类型对象的类型,而不是它恰好存储在其中的引用类型。

【讨论】:

  • @cdhowle 这意味着第二个示例可能属于运行时多态性...
【解决方案2】:

在一种情况下,您正在隐藏方法,而在另一种情况下,您正在覆盖它。不要犹豫,寻求谷歌的帮助,你会得到非常有用的文章或答案。即使在 SO 上,你也会得到很多类似的问题。

   class A
{    
    public void Display()
    {
        Console.WriteLine("A's Method");
    }
}
class B : A
{
    public void Display()
    {
        Console.WriteLine("B's Method");
    }
}

在上面的例子中,你正在做阴影或方法隐藏。如果你使用下面代码中的 new 关键字,你甚至可以获得相同的结果。如果你使用不要在子类的方法中编写覆盖,该方法派生类中的方法不会覆盖基类中的方法,它只是隐藏它。

   public new void Display()
        {
            Console.WriteLine("B's Method");
        }

override 修饰符是扩展或修改继承方法、属性、索引器或事件的抽象或虚拟实现所必需的。因此,要实现覆盖,您必须使用您在第二个示例中使用的 override 关键字。

简单地说,如果一个方法没有覆盖派生方法,它就是隐藏它。覆盖方法提供了从基类继承的成员的新实现。

您也可以在这里查看MSDN 何时进行方法隐藏或何时进行覆盖。

根据评论部分的讨论,我附上下面的代码。希望它会帮助你。

    using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
             A a=new A();
             a.Display();//Parent's Method
             B b =new B();
             b.Display();//Child's Method
             **A ab = new B();
             ab.Display();//Parent's Method**
             Console.ReadKey();
             Parent parent = new Parent();
             parent.Display();//Parent's Method
             Child child = new Child();
             child.Display();//Child's Method
             **Parent ParentChild = new Child();
             ParentChild.Display();//Child's Method**
             Console.ReadKey();
        }
        class A
        {
            public virtual void Display()
            {
                Console.WriteLine("Parent's Method");
            }
        }
        class B : A
        {
            public void Display()
            {
                Console.WriteLine("Child's Method");
            }
        }

        class Parent
        {
            public virtual void Display()
            {
                Console.WriteLine("Parent's Method");
            }
        }
        class Child : Parent
        {
            public override void Display()
            {
                Console.WriteLine("Child's Method");
            }
        }
    }
}

【讨论】:

  • 子(派生)类可以使用基类的方法或函数,而无需使用“覆盖”关键字。编译器隐藏了基类的函数或方法。这个概念被称为阴影或方法隐藏。在阴影或方法隐藏中,子(派生)类有自己的函数版本,同样的函数在基类中也可用。
  • 如果我们使用override,它会改变\覆盖其子类中基类虚方法的定义。
  • 在代码中,B类和C类都打印自己的方法,那么有什么区别.. class A { public virtual void Display() { Console.WriteLine("A's Method"); } } 类 B : A { public override void Display() { Console.WriteLine("B's Method"); } } 类 C : A { public new void Display() { Console.WriteLine("C 的方法"); } }
  • 你有区别吗?
【解决方案3】:

简单地说,多态是指您可以将派生对象视为祖先对象,并让所有派生功能正常运行。

在您的第一个示例中,您隐藏了祖先方法,因此如果您将派生对象视为祖先,那么它的行为就像祖先一样。这不是多态的。

在第二个示例中,您覆盖了祖先方法,因此当您将对象视为祖先时,它的行为仍与派生对象一样。这个多态的。

虽然这是一个简单的概念,但随之而来的还有很多不那么简单的副作用和条件。例如,请参阅Liskov Substitution Principle(我不会在这里介绍)。还有其他原则和理论在起作用。但是,了解 C# 中的多态性主要通过继承来实现就足够了(尽管它也可以通过 ducktyping 使用动态对象和泛型的泛型类型来实现)。

还有几种类型的多态性...有关更多信息,请参阅 Wikipedia 条目:

http://en.wikipedia.org/wiki/Polymorphism_(computer_science)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多