C# - 多态
C# - 多态
Section titled “C# - 多态”多态(polymorphism)一词意为“多种形式”。在面向对象编程中,它允许将不同类的对象视为一个共同超类的对象来处理。它通常被表述为“一个接口,多种实现”。
多态使您能够编写更灵活、更解耦、更易于维护的代码。C# 中主要有两种类型:
- 静态多态(编译时):在编译时决定调用哪个方法。这通过方法重载和运算符重载实现。
- 动态多态(运行时):在运行时才决定调用哪个方法。这通过使用
virtual、override和abstract关键字进行方法重写实现,通常与继承和接口结合使用。
1. 静态多态
Section titled “1. 静态多态”静态多态也称为早期绑定,由编译器解析。
方法重载允许您在同一个类中定义多个同名方法,只要它们的参数列表不同。参数列表的不同体现在参数的数量或参数的类型上。仅返回类型不能用于重载方法。
public class Logger{ // 重载 1:接受一个字符串 public void Log(string message) { Console.WriteLine($"LOG: {message}"); }
// 重载 2:接受一个字符串和一个异常 public void Log(string message, Exception ex) { Console.WriteLine($"ERROR: {message} | Exception: {ex.Message}"); }
// 重载 3:接受一个整数 public void Log(int code) { Console.WriteLine($"Status Code: {code}"); }}
// 使用示例var logger = new Logger();logger.Log("User logged in.");logger.Log(404);logger.Log("Failed to load data.", new InvalidOperationException());
// Output:// LOG: User logged in.// Status Code: 404// ERROR: Failed to load data. | Exception: Operation is not valid due to the current state of the object.C# 允许您为自定义类型重新定义运算符(如 +、-、*、/、==、!=)的行为。这通过使用 operator 关键字声明一个 static 方法来实现。
这里,我们定义了一个 Vector 类型并重载了 + 运算符以执行向量加法。我们使用 record struct 来表示简洁、不可变的值类型。
// 记录结构体非常适合简单、不可变的数据结构public record struct Vector(int X, int Y);
{ // 为两个 Vector 对象重载 + 运算符 public static Vector operator +(Vector v1, Vector v2) { return new Vector(v1.X + v2.X, v1.Y + v2.Y); }}
// 使用示例var vector1 = new Vector(2, 3);var vector2 = new Vector(5, 1);
// 在这里调用了重载的 + 运算符Vector resultVector = vector1 + vector2;
Console.WriteLine($"Vector 1: {vector1}");Console.WriteLine($"Vector 2: {vector2}");Console.WriteLine($"Resultant Vector: {resultVector}");
// Output:// Vector 1: Vector { X = 2, Y = 3 }// Vector 2: Vector { X = 5, Y = 1 }// Resultant Vector: Vector { X = 7, Y = 4 }2. 动态多态
Section titled “2. 动态多态”动态多态也称为后期绑定,在运行时解析,是灵活和可扩展的面向对象设计的基石。
使用 virtual 和 override 进行方法重写
Section titled “使用 virtual 和 override 进行方法重写”基类可以将方法声明为 virtual(虚方法),允许派生类使用 override 关键字提供其特有的实现。在运行时,执行哪个方法的决定是基于对象的实际类型。
// 带有虚方法的基类public class Shape{ public virtual void Draw() { Console.WriteLine("Drawing a generic shape."); }}
// 覆盖方法的派生类public class Circle : Shape{ public override void Draw() { Console.WriteLine("Drawing a circle."); }}
// 另一个派生类public class Square : Shape{ public override void Draw() { Console.WriteLine("Drawing a square."); }}
// 演示多态var shapes = new List<Shape>{ new Shape(), new Circle(), new Square()};
foreach (var shape in shapes){ shape.Draw(); // 在运行时调用正确的 Draw() 方法}
// Output:// Drawing a generic shape.// Drawing a circle.// Drawing a square.抽象类和抽象方法
Section titled “抽象类和抽象方法”一个 abstract(抽象)类不能被实例化,并作为其他类的基类。它可以包含没有实现且必须由任何非抽象派生类重写的 abstract 成员(方法、属性)。
public abstract class Animal{ // 一个抽象属性 - 派生类必须实现它 public abstract string Sound { get; }
// 使用抽象属性的普通方法 public void Speak() { Console.WriteLine($"The animal says: {Sound}"); }}
public class Dog : Animal{ // 实现抽象属性 public override string Sound => "Woof!";}
public class Cat : Animal{ // 实现抽象属性 public override string Sound => "Meow!";}
// 使用示例Animal myDog = new Dog();Animal myCat = new Cat();
myDog.Speak();myCat.Speak();
// Output:// The animal says: Woof!// The animal says: Meow!一个 interface(接口)定义了一个类或结构可以实现的公共成员契约。它是一种在不使用类继承的情况下实现多态的强大方式,从而实现了一种形式的多重继承。
// 定义可发送事物的契约接口public interface ISendable{ void Send();}
// Email 类实现了该接口public class Email : ISendable{ public void Send() => Console.WriteLine("Sending an email...");}
// SMS 类也实现了该接口public class Sms : ISendable{ public void Send() => Console.WriteLine("Sending an SMS...");}
// 此方法适用于任何实现了 ISendable 接口的对象public void SendNotification(ISendable message){ message.Send();}
// 使用示例SendNotification(new Email());SendNotification(new Sms());
// Output:// Sending an email...// Sending an SMS...抽象类 vs. 接口:何时使用?
Section titled “抽象类 vs. 接口:何时使用?”一个常见的问题是何时使用抽象类,何时使用接口。这是一个快速指南:
- 在以下情况使用抽象类:
- 您希望在几个紧密相关的类之间共享代码(方法实现、字段)。
- 您期望扩展您抽象类的类有一个共同的基类,一个“is-a”关系(例如,
Dog是一种Animal)。 - 您需要提供
protected或internal成员。
- 在以下情况使用接口:
- 您期望不相关的类将实现该接口。它定义了一种能力,一种“can-do”关系(例如,
Bird和Plane都可以Fly)。 - 您想指定数据类型的行为,但不需要关心谁实现其行为。
- 您希望利用类型的多重继承。
- 您期望不相关的类将实现该接口。它定义了一种能力,一种“can-do”关系(例如,