我们一起聊聊 C# 方法重写(override)

开发 前端
方法重写是实现多态性的关键,可以使代码更加灵活和可维护。通过在派生类中重写基类的方法,我们可以根据需要改变或扩展基类的行为,而无需修改基类的代码。在设计类的继承结构时,合理地使用方法重写,可以提高代码的质量和可扩展性。

方法重写(Method Overriding)是 C# 面向对象编程中的一个核心概念,它允许派生类根据需要改变继承自基类的方法实现。通过方法重写,可以实现多态性,使程序更加灵活、易于扩展和维护。本文将详细介绍方法重写的特性和应用场景,并通过多个实例加深对这一概念的理解。

实现项目中方法重写比较常用。

方法重写的特性

多态性

  • 定义:多态性允许相同的接口调用,根据对象的实际类型执行不同的操作。
  • 实现:通过在基类中定义虚方法(virtual),在派生类中重写(override)这些方法来实现多态。

灵活性

  • 重写基类的方法,派生类可以根据自身需求修改或扩展方法的实现,而无需修改基类的代码。

可维护性

  • 通过方法重写,可以在不改变基类代码的情况下,对其行为进行修改或扩展,增强了代码的可维护性和可扩展性。

方法重写的应用场景

定制化行为

当派生类需要提供与基类不同的具体实现时,可通过重写基类的方法来实现定制化行为。

扩展基类功能

在不改变基类的情况下,派生类可以通过调用基类方法并添加新的功能来扩展基类的行为。

实现设计模式

某些设计模式(如模板方法模式)需要通过在派生类中重写基类方法来实现特定的业务逻辑。

方法重写的语法与规则

  • 基类方法:使用 virtual 关键字标识可被重写的方法。
public virtual void MethodName()
{
    // 基类方法实现
}
  • 派生类方法:使用 override 关键字重写基类的方法。
public override void MethodName()
{
    // 派生类方法实现
}
  • 调用基类方法:在重写的方法中,可以使用 base.MethodName() 调用基类的方法实现。

实例解析

示例 1:动物叫声

目标:演示如何通过方法重写实现多态性。

namespace App06
{
    public class Animal
    {
        public virtual void Speak()
        {
            Console.WriteLine("动物发出声音。");
        }
    }

    public class Dog : Animal
    {
        public override void Speak()
        {
            Console.WriteLine("狗叫:汪汪!");
        }
    }

    public class Cat : Animal
    {
        public override void Speak()
        {
            Console.WriteLine("猫叫:喵喵!");
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            // 使用示例
            Animal[] animals = { new Dog(), new Cat(), new Animal() };

            foreach (var animal in animals)
            {
                animal.Speak();
            }
        }
    }
}

图片

说明:

  • 基类 Animal 定义了虚方法 Speak()。
  • Dog 和 Cat 类重写了 Speak() 方法,实现各自的叫声。
  • 通过基类引用调用 Speak() 方法,根据实际对象类型执行不同的实现。

示例 2:车辆启动

目标:展示如何在重写的方法中调用基类的方法。

namespace App06
{
    public class Vehicle
    {
        public virtual void Start()
        {
            Console.WriteLine("车辆启动。");
        }
    }

    public class Car : Vehicle
    {
        public override void Start()
        {
            base.Start(); // 调用基类的 Start 方法
            Console.WriteLine("汽车发动引擎。");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            // 使用示例
            Vehicle myCar = new Car();
            myCar.Start();
        }
    }
}

图片

说明:

  • Car 类重写了 Start() 方法,并使用 base.Start() 调用了基类的方法,实现了功能的扩展。

示例 3:图形绘制

目标:演示抽象类和方法重写的结合使用。

namespace App06
{
    public abstract class Shape
    {
        public abstract void Draw();
    }

    public class Circle : Shape
    {
        public override void Draw()
        {
            Console.WriteLine("绘制一个圆形。");
        }
    }

    public class Rectangle : Shape
    {
        public override void Draw()
        {
            Console.WriteLine("绘制一个矩形。");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            // 使用示例
            List<Shape> shapes = new List<Shape>
            {
                new Circle(),
                new Rectangle()
            };

            foreach (var shape in shapes)
            {
                shape.Draw();
            }
        }
    }
}

图片

说明:

  • 抽象类 Shape 定义了抽象方法 Draw(),强制派生类必须实现该方法。
  • 派生类 Circle 和 Rectangle 实现了各自的 Draw() 方法。

示例 4:员工薪资计算

目标:通过方法重写计算不同类型员工的薪资。

namespace App06
{
    public class Employee
    {
        public virtual double CalculateSalary()
        {
            return 3000.0; // 基本工资
        }
    }

    public class Manager : Employee
    {
        public override double CalculateSalary()
        {
            return base.CalculateSalary() + 2000.0; // 基本工资 + 管理奖金
        }
    }

    public class Salesperson : Employee
    {
        public double SalesAmount { get; set; }

        public override double CalculateSalary()
        {
            return base.CalculateSalary() + SalesAmount * 0.05; // 基本工资 + 销售提成
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            // 使用示例
            Employee emp1 = new Manager();
            Employee emp2 = new Salesperson { SalesAmount = 50000 };

            Console.WriteLine($"经理薪资:{emp1.CalculateSalary()}");
            Console.WriteLine($"销售员薪资:{emp2.CalculateSalary()}");
        }
    }
}

图片

说明:

  • Manager 和 Salesperson 重写了 CalculateSalary() 方法,分别计算不同的薪资。
  • 使用基类引用调用方法,实现了对不同员工薪资的多态计算。

示例 5:模板方法模式

目标:通过方法重写实现模板方法模式。

namespace App06
{
    public abstract class DataProcessor
    {
        // 模板方法
        public void ProcessData()
        {
            ReadData();
            Process();
            SaveData();
        }

        protected abstract void ReadData();
        protected abstract void Process();
        protected virtual void SaveData()
        {
            Console.WriteLine("数据已保存。");
        }
    }

    public class ExcelDataProcessor : DataProcessor
    {
        protected override void ReadData()
        {
            Console.WriteLine("从 Excel 文件读取数据。");
        }

        protected override void Process()
        {
            Console.WriteLine("处理 Excel 数据。");
        }
    }

    public class CsvDataProcessor : DataProcessor
    {
        protected override void ReadData()
        {
            Console.WriteLine("从 CSV 文件读取数据。");
        }

        protected override void Process()
        {
            Console.WriteLine("处理 CSV 数据。");
        }

        protected override void SaveData()
        {
            Console.WriteLine("数据已保存到 CSV 文件。");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            // 使用示例
            DataProcessor processor1 = new ExcelDataProcessor();
            processor1.ProcessData();

            DataProcessor processor2 = new CsvDataProcessor();
            processor2.ProcessData();
        }
    }
}

图片图片

说明:

  • 基类 DataProcessor 定义了模板方法 ProcessData(),并声明了一些抽象方法。
  • 派生类实现了这些抽象方法,定制了具体的处理步骤。

注意事项

  • 方法签名一致:重写的方法必须与基类的方法具有相同的签名,包括方法名、参数类型和返回类型。
  • 访问修饰符:重写的方法的访问级别不能低于基类中被重写的方法。
  • sealed 关键字:如果不希望派生类进一步重写某个方法,可以在方法前添加 sealed 关键字。
public override sealed void MethodName()
{
    // 实现
}

总结

方法重写是实现多态性的关键,可以使代码更加灵活和可维护。通过在派生类中重写基类的方法,我们可以根据需要改变或扩展基类的行为,而无需修改基类的代码。在设计类的继承结构时,合理地使用方法重写,可以提高代码的质量和可扩展性。

建议:

  • 在基类中,预期可能被修改的方法应声明为 virtual 或 abstract。
  • 在派生类中,重写方法时确保方法签名正确,并考虑是否需要调用 base 方法。
  • 谨慎使用方法重写,避免造成代码的混乱和难以维护。
责任编辑:武晓燕 来源: 技术老小子
相关推荐

2024-11-28 09:57:50

C#事件发布器

2023-10-10 08:00:07

2024-08-26 08:34:47

AES加密算法

2025-01-09 07:54:03

2024-08-30 11:00:22

2024-12-23 10:20:50

2022-05-24 08:21:16

数据安全API

2023-08-10 08:28:46

网络编程通信

2023-06-30 08:18:51

敏捷开发模式

2023-08-04 08:20:56

DockerfileDocker工具

2023-09-10 21:42:31

2024-02-20 21:34:16

循环GolangGo

2021-08-27 07:06:10

IOJava抽象

2024-05-29 13:18:12

线程Thread​方式

2024-11-11 11:33:57

2022-06-26 09:40:55

Django框架服务

2022-10-28 07:27:17

Netty异步Future

2022-11-12 12:33:38

CSS预处理器Sass

2023-12-28 09:55:08

队列数据结构存储

2023-04-26 07:30:00

promptUI非结构化
点赞
收藏

51CTO技术栈公众号