美文网首页
C#多态性

C#多态性

作者: 86a262e62b0b | 来源:发表于2019-10-16 13:16 被阅读0次

参考文档:
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/polymorphism

一. 概念

多态性:指多种形态,具有两个截然不同的方面:

  • 在运行时,在方法参数和集合或数组等位置,派生类的对象可以作为基类的对象处理。 发生此情况时,该对象的声明类型不再与运行时类型相同。
  • 基类可以定义并实现虚方法,派生类可以重写这些方法,即派生类提供自己的定义和实现 。 在运行时,客户端代码调用该方法,CLR 查找对象的运行时类型,并调用虚方法的重写方法。 因此,你可以在源代码中调用基类的方法,但执行该方法的派生类版本。

二. 基本使用

当派生类从基类继承时,它会获得基类的所有方法、字段、属性和事件。
派生类可以选择以下处理:

1. 重写基类中的虚拟成员,或不重写

注意:

  • 仅当基类成员声明为 virtualabstract 时,派生类才能重写基类成员
  • 字段不能是虚拟的,只有方法、属性、事件和索引器才可以是虚拟的。

示例:

public class BaseClass
{
    public virtual void DoWork() { }
    public virtual int WorkProperty
    {
        get { return 0; }
    }
}
public class DerivedClass : BaseClass
{
    public override void DoWork() { }
    public override int WorkProperty
    {
        get { return 0; }
    }
}

//当派生类重写某个虚拟成员时,即使该派生类的实例被当作基类的实例访问,也会调用该成员。
DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork();  // Also calls the new method.

2. 使用新成员隐藏基类成员

如果希望派生成员具有与基类中的成员相同的名称,但又不希望派生成员参与虚调用,则可以使用 new 关键字。

public class BaseClass
{
    public void DoWork() { WorkField++; }
    public int WorkField;
    public int WorkProperty
    {
        get { return 0; }
    }
}

public class DerivedClass : BaseClass
{
    public new void DoWork() { WorkField++; }
    public new int WorkField;
    public new int WorkProperty
    {
        get { return 0; }
    }
}

//通过将派生类的实例强制转换为基类的实例,仍然可以从客户端代码访问隐藏的基类成员。
DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork();  // Calls the old method.

3. 阻止派生类重写虚拟成员

  • 无论在虚拟成员和最初声明虚拟成员的类之间已声明了多少个类,虚拟成员永远都是虚拟的。 如果类 A 声明了一个虚拟成员,类 B 从 A 派生,类 C 从类 B 派生,则类 C 继承该虚拟成员,并且可以选择重写它,而不管类 B 是否为该成员声明了重写。

  • 派生类可以通过将重写声明为 sealed 来停止虚拟继承。 这需要在类成员声明中的 override 关键字前面放置 sealed 关键字。 以下代码提供了一个示例:

public class A
{
    public virtual void DoWork() { }
}
public class B : A
{
    public override void DoWork() { }
}
public class C : B
{
    public sealed override void DoWork() { }
}

在上一示例中,方法 DoWork 对从 C 派生的任何类都不再是虚方法。它对 C 的实例仍是虚拟的,即使它们转换为类型 B 或类型 A。

  • 使用 new 关键字可以将密封方法替换为派生类,如下方示例所示:
public class D : C
{
    public new void DoWork() { }
}
  1. 在此情况下,如果在 D 中使用类型为 D 的变量调用 DoWork,被调用的将是新的 DoWork。
  2. 如果使用类型为 C、B 或 A 的变量访问 D 的实例,对 DoWork 的调用将遵循虚拟继承的规则,即把这些调用传送到类 C 的 DoWork 实现。

三. 方法的选择

public class Derived : Base
{
    public override void DoWork(int param) { }
    public void DoWork(double param) { }
}

int val = 5;
Derived d = new Derived();
d.DoWork(val);  // Calls DoWork(double).
  • 在 Derived 的一个实例中调用 DoWork 时,C# 编译器将首先尝试使该调用与最初在 Derived 上声明的 DoWork 版本兼容(方法名相同,参数类型可隐式转换)。
  • 替代方法不被视为是在类上进行声明的,而是在基类上声明的方法的新实现。
  • 仅当 C# 编译器无法将方法调用与 Derived 上的原始方法匹配时,才尝试将该调用与具有相同名称和兼容参数的替代方法匹配。

=>

由于变量 val 可以隐式转换为 double 类型,因此 C# 编译器将调用 DoWork(double),而不是 DoWork(int)。

有两种方法可以避免此情况:

  1. 首先,避免将新方法声明为与虚方法相同的名称。
  2. 其次,可以通过将 Derived 的实例强制转换为 Base 来使 C# 编译器搜索基类方法列表,从而使其调用虚方法。 又由于是虚方法,因此将调用 Derived 上的 DoWork(int) 的实现。 例如:
((Base)d).DoWork(val);  // Calls DoWork(int) on Derived.

四.

更多案例请参考文档:
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/knowing-when-to-use-override-and-new-keywords

五. How to: Override the ToString Method

C# 中的每个类或结构都可隐式继承 Object 类。 因此,C# 中的每个对象都会获取 ToString 方法,

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override string ToString()
    {
        return "Person: " + Name + " " + Age;
    }
}

相关文章

  • Rust中的三种多态性——Enum和Trait(上)

    0x01 开篇 多态性(Polymorphism)在很多语言中都存在,比如Java/C#等。有了编程语言的多态性会...

  • C#多态性

    参考文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/progr...

  • Rust中的三种多态性——Trait的两种方式(中)

    0x01 回顾与开篇 多态性(Polymorphism)在很多语言中都存在,比如Java/C#等。有了编程语言的多...

  • Rust中的三种多态性——枚举+结构体(下)

    0x00 回顾与开篇 多态性(Polymorphism)在很多语言中都存在,比如Java/C#等。有了编程语言的多...

  • C#基础知识2

    动态多态性 C# 允许您使用关键字abstract创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象...

  • 详解Java多态

    详解Java多态 多态定义 多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态...

  • C#魔帅-lesson_03-多态性

    多态性 多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。多态性可以是静态的或...

  • JAVA面向对象学习(多态性)

    多态性的理解和应用 1.1. 多态性的理解 多态性:在Java中,多态性是它的一大特性,可以理解成为是事物的多种形...

  • 多态

    面向对象特征之三:多态性 1、理解多态性:一个事物的多种形态 2、什么是多态性?对象的多态性:父类的引用指向子类的...

  • 第五章多态性

    第5章 多态性 一、编译时的多态性和运行时的多态性 多态性是指用一个名字定义不同的函数,这些函数执行不同但又类似的...

网友评论

      本文标题:C#多态性

      本文链接:https://www.haomeiwen.com/subject/vqzfyctx.html