探索基于继承的多态性
基于继承的多态性基于类层次结构,其中派生类从基类继承行为和属性。 利用继承关系,可以将派生类的对象视为基类的对象。 通过能够将派生类对象视为基类对象,可以编写处理多种类型的对象的代码,而无需在编译时知道特定类型。
以下代码示例演示 C# 中基于继承的多态性:
// Base class
public class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("The animal makes a sound.");
}
}
// Derived class Dog
public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("The dog barks.");
}
}
// Derived class Cat
public class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine("The cat meows.");
}
}
// Derived class Cow
public class Cow : Animal
{
public override void MakeSound()
{
Console.WriteLine("The cow moos.");
}
}
class Program
{
static void Main()
{
// Create an array of Animal objects
Animal[] animals = new Animal[3];
Animal animal1 = new Dog();
Animal animal2 = new Cat();
Animal animal3 = new Cow();
animals[0] = animal1;
animals[1] = animal2;
animals[2] = animal3;
// Demonstrate polymorphism
foreach (Animal animal in animals)
{
animal.MakeSound();
}
}
}
在此示例代码中,请注意,Program 类会创建一个 Animal 对象的数组,并将 Dog、Cat和 Cow 的实例分配给数组元素。 MakeSound 方法在数组中的每个对象上调用,演示多态性。 MakeSound 方法在派生类中被替代,以便为每个动物类型提供特定行为。
将基类的对象强制转换为派生类
在 C# 中强制转换是将一种类型的对象转换为另一种类型的过程。 使用继承层次结构实现多态性时,通常使用强制转换,其中你有一个基类和一个或多个派生类。
有两种主要的强制转换类型:
隐式强制转换:将派生类转换为基类时,会自动发生这种情况。 这是安全的,因为派生类的每个实例也是基类的实例。
BankAccount account = new CheckingAccount();显式强制转换:这需要强制转换运算符,在将基类转换为派生类时使用。 它并不总是安全的,因为并非基类的每个实例都是派生类的实例。
CheckingAccount checkingAccount = (CheckingAccount)account;
使用 is 和 as 关键字强制转换对象
在 C# 中,可以使用 is 和 as 关键字强制转换对象。 这些关键字提供了一种安全的方法,用于在将对象转换为另一种类型之前检查对象的类型。 下面是在 C# 中强制转换对象的一些常见方法:
将
is关键字与模式匹配结合使用:if (account is CheckingAccount checkingAccount) { // Use checkingAccount as a CheckingAccount }- 此语法会检查
account的类型是否为CheckingAccount。 - 如果检查成功,它会将
account强制转换为CheckingAccount并将其分配给变量checkingAccount。 - 此方法简洁且安全,因为它将类型检查合并在一步中并强制转换。
- 此语法会检查
使用
is关键字,后跟显式强制转换:if (account is CheckingAccount) { CheckingAccount checkingAccount = (CheckingAccount)account; // Use checkingAccount as a CheckingAccount }- 此语法会检查
account的类型是否为CheckingAccount。 - 如果检查成功,它会显式将
account强制转换为CheckingAccount并将其分配给变量checkingAccount。 - 此方法比模式匹配语法更详细,但可以更好地控制强制转换过程。
- 此语法会检查
使用
as关键字:CheckingAccount checkingAccount = account as CheckingAccount; if (checkingAccount != null) { // Use checkingAccount as a CheckingAccount }- 此语法会尝试将
account强制转换为CheckingAccount,并将结果分配给checkingAccount。 - 如果强制转换成功,
checkingAccount会包含强制转换对象;否则它为 null。 - 如果想要在使用强制转换对象之前检查强制转换结果,此方法非常有用。 例如,当你想要避免异常并正常处理失败情况时。
- 此语法会尝试将
实现强制转换时,请考虑以下准则:
- 通过
is使用模式匹配:在一个步骤中合并类型检查和强制转换。 - 将
is关键字与显式强制转换结合使用:将类型检查和强制转换为两个步骤,从而更好地控制强制转换过程。 - 使用
as关键字:尝试通过返回 null 来正常强制转换和处理失败。
- 通过
了解这些强制转换技术对于在 C# 中使用多态性和继承至关重要。
实现多态性时避免常见陷阱
当你的目标是基于继承的多态性时,下面是一些要避免的事项,以及一些要确保的事项:
避免使用密封类和方法:密封类和方法无法继承或替代,这限制了使用多态性的能力。 如果密封类或方法,将阻止进一步扩展和自定义。 例如:
public sealed class BankAccount { } // This class can't be inherited避免过度使用静态方法。 静态方法属于类本身,而不是类的实例。 它们不能被替代,这意味着他们不参与多态性。
public static void PrintMessage() { } // This method can't be overridden避免紧密耦合。 当系统中的类或组件彼此高度依赖时,会发生紧密耦合。 这意味着一个类中的更改可能会直接影响其他类,从而使系统更加灵活且难以维护。 紧密耦合可能会导致测试、扩展和修改代码时遇到困难。
public class BankAccount { public void TransferFunds(SavingsAccount savingsAccount) { // Tight coupling with SavingsAccount } }避免在没有充分理由的情况下使用“new”关键字。 “new”关键字隐藏派生类中的基类方法,这可能会导致混淆和意外行为。 仅当打算有意隐藏基类方法时,才使用“new”关键字。
public class Dog : Animal { public new void MakeSound() // Hides the base class method. Better to use 'override' { Console.WriteLine("The dog barks."); } }确保方法签名一致。 确保派生类中的替代方法具有与基类方法相同的签名。 更改方法签名将导致方法隐藏而不是替代。
public class Animal { public virtual void MakeSound(string sound) { Console.WriteLine("The animal makes a sound."); } } public class Dog : Animal { // Method signature doesn't match the base class public override void MakeSound() { Console.WriteLine("The dog barks."); } }
摘要
使用 C# 中基于继承的多态性,可以创建派生类从基类继承行为和属性的类层次结构。 使用此继承机制可以将派生类的对象视为基类的对象。 将派生类对象视为基类的成员的功能使你能够编写处理多种类型的对象的代码,而无需在编译时知道特定类型。 通过了解强制转换技术、避免常见陷阱和遵循最佳做法,可以在 C# 应用程序中有效地实现多态性。