Menu
CoddyTech

编译时多态与运行时多态

本课属于 Coddy C# 学习旅程的“面向对象编程”单元。第 25 课,共 70 课。

多态意味着“多种形式”,也就是说,同一段代码可以根据上下文表现出不同的行为。C# 支持两种不同的多态,了解它们各自在何时确定,有助于你编写更灵活的代码。

编译时多态(也称为静态多态)由编译器在程序运行前解析。方法重载是最主要的例子:多个方法使用相同的名称,但参数不同:

public class Calculator
{
    public int Add(int a, int b) => a + b;
    public double Add(double a, double b) => a + b;
}

var calc = new Calculator();
calc.Add(5, 3);       // 编译器选择 int 版本
calc.Add(5.0, 3.0);   // 编译器选择 double 版本

编译器会检查参数类型,并在编译时选择正确的方法。程序运行之前,这个决定就已确定。

运行时多态(动态多态)在程序运行时确定。这会通过 virtual 和 override 方法实现,实际的对象类型决定执行哪个方法:

Animal pet = new Dog();  // 声明为 Animal,实际上是 Dog
pet.Speak();             // 运行时调用 Dog 的 Speak()

编译器不知道会运行哪个 Speak(),这个决定会在运行时根据对象的实际类型作出。这就是基于继承的多态在构建灵活、可扩展的系统时如此强大的原因。

challenge icon

挑战

简单

我们来构建一个转换器系统,展示两种多态的实际效果。你将创建一个使用方法重载(编译时多态)的类,以及一个使用 virtual/override 方法的继承层次结构(运行时多态)。

你将把代码分放在 4 个文件中:

  • Converter.cs:在 Conversion 命名空间中定义一个 Converter 类。这个类通过方法重载展示编译时多态。创建 3 个重载的 Convert 方法:
    • Convert(int value) 返回 "Integer: {value}"
    • Convert(double value) 返回 "Double: {value}"
    • Convert(string value) 返回 "String: {value}"
  • Shape.cs:在 Conversion 命名空间中定义一个基类 Shape。这个类有一个 Name 属性(字符串),以及一个用于设置该属性的构造函数。添加一个名为 Describe() 的 virtual 方法,返回 "This is a {Name}"。
  • Circle.cs:在 Conversion 命名空间中定义一个继承自 Shape 的 Circle 类。添加一个 Radius 属性(double)。构造函数接收一个半径,并将 "Circle" 传给基类构造函数。重写 Describe(),使其返回 "This is a Circle with radius {Radius}"。
  • Program.cs:在主文件中展示两种多态。首先,创建一个 Converter,并使用输入值调用全部 3 个重载方法。然后创建一个 Circle,将它存储在一个 Shape 变量中,并调用 Describe() 来展示运行时多态。

你将收到 4 个输入:

  • 一个整数值
  • 一个 double 值
  • 一个字符串值
  • 一个圆的半径(double)

按以下格式打印输出:

Compile-time Polymorphism:
{Convert(int) result}
{Convert(double) result}
{Convert(string) result}
Runtime Polymorphism:
{Describe() result from Shape variable holding Circle}

例如,如果输入是 42、3.14、Hello 和 5.5,输出应为:

Compile-time Polymorphism:
Integer: 42
Double: 3.14
String: Hello
Runtime Polymorphism:
This is a Circle with radius 5.5

注意这个关键区别:编译器会在编译时根据参数类型决定调用哪个 Convert 方法,而 Describe() 方法会在运行时根据实际对象类型确定,即使它存储在一个 Shape 变量中也是如此!

亲手试试

using System;
using Conversion;

class Program
{
    public static void Main(string[] args)
    {
        // 读取输入
        int intValue = Convert.ToInt32(Console.ReadLine());
        double doubleValue = Convert.ToDouble(Console.ReadLine());
        string stringValue = Console.ReadLine();
        double radius = Convert.ToDouble(Console.ReadLine());

        // TODO:演示编译时多态
        // 创建一个 Converter 对象,并调用全部三个重载的 Convert 方法
        Console.WriteLine("Compile-time Polymorphism:");
        // 分别用 intValue、doubleValue 和 stringValue 调用 Convert

        // TODO:演示运行时多态
        // 创建一个 Circle 对象,并将它存入 Shape 变量
        // 然后通过 Shape 变量调用 Describe()
        Console.WriteLine("Runtime Polymorphism:");
        // 创建 Circle 对象并调用 Describe()
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C# 在线编译器