本章目标

通过本章学习,你将掌握: - 继承的概念和实现 - 方法重写和虚方法 - 抽象类和抽象方法 - 接口的定义和实现 - 多态的概念和应用 - base和this关键字的使用 - 密封类和密封方法 - 类型转换和类型检查

1. 继承基础

1.1 继承的概念

继承是面向对象编程的核心特性之一,它允许一个类(子类/派生类)继承另一个类(父类/基类)的属性和方法。

// 基类(父类)
public class Animal
{
    protected string name;
    protected int age;
    protected double weight;
    
    public string Name
    {
        get => name;
        set => name = value ?? throw new ArgumentNullException(nameof(value));
    }
    
    public int Age
    {
        get => age;
        set => age = value >= 0 ? value : throw new ArgumentException("年龄不能为负数");
    }
    
    public double Weight
    {
        get => weight;
        set => weight = value > 0 ? value : throw new ArgumentException("体重必须大于0");
    }
    
    // 构造函数
    public Animal(string name, int age, double weight)
    {
        Name = name;
        Age = age;
        Weight = weight;
    }
    
    // 虚方法 - 可以被子类重写
    public virtual void Eat()
    {
        Console.WriteLine($"{name} 正在吃东西");
    }
    
    public virtual void Sleep()
    {
        Console.WriteLine($"{name} 正在睡觉");
    }
    
    public virtual void Move()
    {
        Console.WriteLine($"{name} 正在移动");
    }
    
    // 普通方法
    public void Breathe()
    {
        Console.WriteLine($"{name} 正在呼吸");
    }
    
    public virtual void MakeSound()
    {
        Console.WriteLine($"{name} 发出声音");
    }
    
    public virtual string GetInfo()
    {
        return $"动物: {name}, 年龄: {age}, 体重: {weight}kg";
    }
}

// 派生类(子类)
public class Dog : Animal
{
    private string breed;
    private bool isTrained;
    
    public string Breed
    {
        get => breed;
        set => breed = value ?? "未知品种";
    }
    
    public bool IsTrained
    {
        get => isTrained;
        set => isTrained = value;
    }
    
    // 构造函数 - 调用基类构造函数
    public Dog(string name, int age, double weight, string breed) : base(name, age, weight)
    {
        Breed = breed;
        IsTrained = false;
    }
    
    public Dog(string name, int age, double weight, string breed, bool isTrained) 
        : this(name, age, weight, breed)
    {
        IsTrained = isTrained;
    }
    
    // 重写基类的虚方法
    public override void Eat()
    {
        Console.WriteLine($"狗狗 {name} 正在吃狗粮");
    }
    
    public override void Move()
    {
        Console.WriteLine($"狗狗 {name} 正在奔跑");
    }
    
    public override void MakeSound()
    {
        Console.WriteLine($"狗狗 {name} 在汪汪叫");
    }
    
    public override string GetInfo()
    {
        string baseInfo = base.GetInfo(); // 调用基类方法
        return $"{baseInfo}, 品种: {breed}, 训练状态: {(isTrained ? "已训练" : "未训练")}";
    }
    
    // 子类特有的方法
    public void Bark()
    {
        Console.WriteLine($"{name} 汪汪汪!");
    }
    
    public void Fetch()
    {
        if (isTrained)
        {
            Console.WriteLine($"{name} 去捡球了");
        }
        else
        {
            Console.WriteLine($"{name} 还没学会捡球");
        }
    }
    
    public void Train()
    {
        if (!isTrained)
        {
            isTrained = true;
            Console.WriteLine($"{name} 训练完成!");
        }
        else
        {
            Console.WriteLine($"{name} 已经训练过了");
        }
    }
    
    public void GuardHouse()
    {
        Console.WriteLine($"{name} 正在看家护院");
    }
}

public class Cat : Animal
{
    private bool isIndoor;
    private int livesRemaining;
    
    public bool IsIndoor
    {
        get => isIndoor;
        set => isIndoor = value;
    }
    
    public int LivesRemaining
    {
        get => livesRemaining;
        private set => livesRemaining = Math.Max(0, Math.Min(9, value));
    }
    
    public Cat(string name, int age, double weight, bool isIndoor = true) : base(name, age, weight)
    {
        IsIndoor = isIndoor;
        LivesRemaining = 9; // 猫有九条命
    }
    
    public override void Eat()
    {
        Console.WriteLine($"猫咪 {name} 正在优雅地吃猫粮");
    }
    
    public override void Move()
    {
        Console.WriteLine($"猫咪 {name} 正在轻盈地走动");
    }
    
    public override void MakeSound()
    {
        Console.WriteLine($"猫咪 {name} 在喵喵叫");
    }
    
    public override void Sleep()
    {
        Console.WriteLine($"猫咪 {name} 正在舒适地睡觉(一天要睡16小时)");
    }
    
    public override string GetInfo()
    {
        string baseInfo = base.GetInfo();
        return $"{baseInfo}, 居住环境: {(isIndoor ? "室内" : "室外")}, 剩余生命: {livesRemaining}";
    }
    
    // 猫特有的方法
    public void Meow()
    {
        Console.WriteLine($"{name} 喵~");
    }
    
    public void Purr()
    {
        Console.WriteLine($"{name} 发出呼噜呼噜的声音");
    }
    
    public void ClimbTree()
    {
        if (!isIndoor)
        {
            Console.WriteLine($"{name} 爬上了树");
        }
        else
        {
            Console.WriteLine($"{name} 是室内猫,不能爬树");
        }
    }
    
    public void CatchMouse()
    {
        Console.WriteLine($"{name} 抓到了一只老鼠");
    }
    
    public void UseLitter()
    {
        if (isIndoor)
        {
            Console.WriteLine($"{name} 使用了猫砂盆");
        }
        else
        {
            Console.WriteLine($"{name} 在外面解决了");
        }
    }
    
    public void LoseLife()
    {
        if (livesRemaining > 0)
        {
            LivesRemaining--;
            Console.WriteLine($"{name} 失去了一条命,还剩 {livesRemaining} 条命");
        }
        else
        {
            Console.WriteLine($"{name} 已经没有生命了");
        }
    }
}

1.2 继承的使用示例

public class InheritanceDemo
{
    public static void Main()
    {
        Console.WriteLine("=== 继承演示 ===");
        
        // 创建基类对象
        Animal animal = new Animal("通用动物", 5, 10.5);
        Console.WriteLine(animal.GetInfo());
        animal.Eat();
        animal.Sleep();
        animal.Move();
        animal.MakeSound();
        animal.Breathe();
        
        Console.WriteLine();
        
        // 创建派生类对象
        Dog dog = new Dog("旺财", 3, 25.0, "金毛");
        Console.WriteLine(dog.GetInfo());
        dog.Eat();      // 调用重写的方法
        dog.Sleep();    // 调用继承的方法
        dog.Move();     // 调用重写的方法
        dog.MakeSound(); // 调用重写的方法
        dog.Breathe();  // 调用继承的方法
        
        // 调用子类特有的方法
        dog.Bark();
        dog.Fetch();
        dog.Train();
        dog.Fetch();
        dog.GuardHouse();
        
        Console.WriteLine();
        
        Cat cat = new Cat("咪咪", 2, 4.5, true);
        Console.WriteLine(cat.GetInfo());
        cat.Eat();
        cat.Sleep();
        cat.Move();
        cat.MakeSound();
        
        // 调用猫特有的方法
        cat.Meow();
        cat.Purr();
        cat.ClimbTree();
        cat.CatchMouse();
        cat.UseLitter();
        cat.LoseLife();
        
        Console.WriteLine();
        
        // 多态演示
        Console.WriteLine("=== 多态演示 ===");
        Animal[] animals = { animal, dog, cat };
        
        foreach (Animal a in animals)
        {
            Console.WriteLine($"\n{a.GetInfo()}");
            a.Eat();        // 根据实际类型调用相应的方法
            a.MakeSound();  // 多态行为
        }
    }
}

2. 抽象类和抽象方法

2.1 抽象类的定义

抽象类是不能被实例化的类,通常用作其他类的基类。

// 抽象基类
public abstract class Shape
{
    protected string name;
    protected string color;
    
    public string Name => name;
    public string Color => color;
    
    // 构造函数
    protected Shape(string name, string color)
    {
        this.name = name;
        this.color = color;
    }
    
    // 抽象方法 - 必须在派生类中实现
    public abstract double CalculateArea();
    public abstract double CalculatePerimeter();
    
    // 虚方法 - 可以在派生类中重写
    public virtual void Draw()
    {
        Console.WriteLine($"绘制{color}的{name}");
    }
    
    // 普通方法 - 可以直接继承
    public void DisplayInfo()
    {
        Console.WriteLine($"形状: {name}");
        Console.WriteLine($"颜色: {color}");
        Console.WriteLine($"面积: {CalculateArea():F2}");
        Console.WriteLine($"周长: {CalculatePerimeter():F2}");
    }
    
    // 抽象属性
    public abstract string ShapeType { get; }
}

// 圆形类
public class Circle : Shape
{
    private double radius;
    
    public double Radius
    {
        get => radius;
        set => radius = value > 0 ? value : throw new ArgumentException("半径必须大于0");
    }
    
    public Circle(double radius, string color = "白色") : base("圆形", color)
    {
        Radius = radius;
    }
    
    // 实现抽象方法
    public override double CalculateArea()
    {
        return Math.PI * radius * radius;
    }
    
    public override double CalculatePerimeter()
    {
        return 2 * Math.PI * radius;
    }
    
    // 实现抽象属性
    public override string ShapeType => "圆形";
    
    // 重写虚方法
    public override void Draw()
    {
        Console.WriteLine($"绘制半径为{radius}的{color}{name}");
    }
    
    // 圆形特有的方法
    public double CalculateDiameter()
    {
        return 2 * radius;
    }
}

// 矩形类
public class Rectangle : Shape
{
    private double width;
    private double height;
    
    public double Width
    {
        get => width;
        set => width = value > 0 ? value : throw new ArgumentException("宽度必须大于0");
    }
    
    public double Height
    {
        get => height;
        set => height = value > 0 ? value : throw new ArgumentException("高度必须大于0");
    }
    
    public Rectangle(double width, double height, string color = "白色") : base("矩形", color)
    {
        Width = width;
        Height = height;
    }
    
    public override double CalculateArea()
    {
        return width * height;
    }
    
    public override double CalculatePerimeter()
    {
        return 2 * (width + height);
    }
    
    public override string ShapeType => "矩形";
    
    public override void Draw()
    {
        Console.WriteLine($"绘制{width}x{height}的{color}{name}");
    }
    
    // 矩形特有的方法
    public bool IsSquare()
    {
        return Math.Abs(width - height) < 0.001;
    }
    
    public double CalculateDiagonal()
    {
        return Math.Sqrt(width * width + height * height);
    }
}

// 三角形类
public class Triangle : Shape
{
    private double sideA;
    private double sideB;
    private double sideC;
    
    public double SideA
    {
        get => sideA;
        set => sideA = value > 0 ? value : throw new ArgumentException("边长必须大于0");
    }
    
    public double SideB
    {
        get => sideB;
        set => sideB = value > 0 ? value : throw new ArgumentException("边长必须大于0");
    }
    
    public double SideC
    {
        get => sideC;
        set => sideC = value > 0 ? value : throw new ArgumentException("边长必须大于0");
    }
    
    public Triangle(double sideA, double sideB, double sideC, string color = "白色") : base("三角形", color)
    {
        // 验证三角形的有效性
        if (!IsValidTriangle(sideA, sideB, sideC))
        {
            throw new ArgumentException("无效的三角形边长");
        }
        
        SideA = sideA;
        SideB = sideB;
        SideC = sideC;
    }
    
    private static bool IsValidTriangle(double a, double b, double c)
    {
        return a + b > c && a + c > b && b + c > a;
    }
    
    public override double CalculateArea()
    {
        // 使用海伦公式
        double s = (sideA + sideB + sideC) / 2;
        return Math.Sqrt(s * (s - sideA) * (s - sideB) * (s - sideC));
    }
    
    public override double CalculatePerimeter()
    {
        return sideA + sideB + sideC;
    }
    
    public override string ShapeType => "三角形";
    
    public override void Draw()
    {
        Console.WriteLine($"绘制边长为{sideA}, {sideB}, {sideC}的{color}{name}");
    }
    
    // 三角形特有的方法
    public string GetTriangleType()
    {
        if (Math.Abs(sideA - sideB) < 0.001 && Math.Abs(sideB - sideC) < 0.001)
            return "等边三角形";
        else if (Math.Abs(sideA - sideB) < 0.001 || Math.Abs(sideB - sideC) < 0.001 || Math.Abs(sideA - sideC) < 0.001)
            return "等腰三角形";
        else
            return "普通三角形";
    }
    
    public bool IsRightTriangle()
    {
        double[] sides = { sideA, sideB, sideC };
        Array.Sort(sides);
        
        // 勾股定理检验
        return Math.Abs(sides[0] * sides[0] + sides[1] * sides[1] - sides[2] * sides[2]) < 0.001;
    }
}

2.2 抽象类使用示例

public class AbstractClassDemo
{
    public static void Main()
    {
        Console.WriteLine("=== 抽象类演示 ===");
        
        // 不能实例化抽象类
        // Shape shape = new Shape("形状", "红色"); // 编译错误
        
        // 创建具体的形状对象
        Circle circle = new Circle(5.0, "红色");
        Rectangle rectangle = new Rectangle(4.0, 6.0, "蓝色");
        Triangle triangle = new Triangle(3.0, 4.0, 5.0, "绿色");
        
        // 使用多态
        Shape[] shapes = { circle, rectangle, triangle };
        
        foreach (Shape shape in shapes)
        {
            Console.WriteLine($"\n=== {shape.ShapeType} ===");
            shape.DisplayInfo();
            shape.Draw();
            
            // 类型特定的操作
            if (shape is Circle c)
            {
                Console.WriteLine($"直径: {c.CalculateDiameter():F2}");
            }
            else if (shape is Rectangle r)
            {
                Console.WriteLine($"是否为正方形: {r.IsSquare()}");
                Console.WriteLine($"对角线长度: {r.CalculateDiagonal():F2}");
            }
            else if (shape is Triangle t)
            {
                Console.WriteLine($"三角形类型: {t.GetTriangleType()}");
                Console.WriteLine($"是否为直角三角形: {t.IsRightTriangle()}");
            }
        }
        
        // 计算总面积
        double totalArea = shapes.Sum(s => s.CalculateArea());
        Console.WriteLine($"\n所有形状的总面积: {totalArea:F2}");
    }
}

3. 接口

3.1 接口的定义和实现

接口定义了类必须实现的成员,但不提供实现。

// 可绘制接口
public interface IDrawable
{
    void Draw();
    void Erase();
    string GetDrawingInfo();
}

// 可移动接口
public interface IMovable
{
    void Move(double deltaX, double deltaY);
    void MoveTo(double x, double y);
    (double X, double Y) Position { get; }
}

// 可缩放接口
public interface IScalable
{
    void Scale(double factor);
    void ScaleTo(double newSize);
    double Size { get; }
}

// 可旋转接口
public interface IRotatable
{
    void Rotate(double angle);
    void RotateTo(double angle);
    double Rotation { get; }
}

// 图形元素基类
public abstract class GraphicElement : IDrawable, IMovable
{
    protected double x, y;
    protected string color;
    protected bool isVisible;
    
    public (double X, double Y) Position => (x, y);
    public string Color => color;
    public bool IsVisible => isVisible;
    
    protected GraphicElement(double x, double y, string color)
    {
        this.x = x;
        this.y = y;
        this.color = color;
        this.isVisible = true;
    }
    
    // 实现IMovable接口
    public virtual void Move(double deltaX, double deltaY)
    {
        x += deltaX;
        y += deltaY;
        Console.WriteLine($"移动到位置 ({x:F1}, {y:F1})");
    }
    
    public virtual void MoveTo(double x, double y)
    {
        this.x = x;
        this.y = y;
        Console.WriteLine($"移动到位置 ({x:F1}, {y:F1})");
    }
    
    // 实现IDrawable接口(部分)
    public virtual void Erase()
    {
        isVisible = false;
        Console.WriteLine($"擦除{GetType().Name}");
    }
    
    public virtual string GetDrawingInfo()
    {
        return $"{GetType().Name} at ({x:F1}, {y:F1}), Color: {color}, Visible: {isVisible}";
    }
    
    // 抽象方法
    public abstract void Draw();
    
    // 通用方法
    public void Show()
    {
        isVisible = true;
        Console.WriteLine($"显示{GetType().Name}");
    }
    
    public void Hide()
    {
        isVisible = false;
        Console.WriteLine($"隐藏{GetType().Name}");
    }
}

// 圆形图形元素
public class GraphicCircle : GraphicElement, IScalable
{
    private double radius;
    
    public double Radius => radius;
    public double Size => radius;
    
    public GraphicCircle(double x, double y, double radius, string color = "黑色") 
        : base(x, y, color)
    {
        this.radius = radius > 0 ? radius : throw new ArgumentException("半径必须大于0");
    }
    
    public override void Draw()
    {
        if (isVisible)
        {
            Console.WriteLine($"绘制{color}圆形:中心({x:F1}, {y:F1}),半径{radius:F1}");
        }
    }
    
    // 实现IScalable接口
    public void Scale(double factor)
    {
        if (factor <= 0)
            throw new ArgumentException("缩放因子必须大于0");
            
        radius *= factor;
        Console.WriteLine($"圆形缩放{factor}倍,新半径:{radius:F1}");
    }
    
    public void ScaleTo(double newSize)
    {
        if (newSize <= 0)
            throw new ArgumentException("新大小必须大于0");
            
        radius = newSize;
        Console.WriteLine($"圆形大小设置为:{radius:F1}");
    }
    
    public double CalculateArea()
    {
        return Math.PI * radius * radius;
    }
}

// 矩形图形元素
public class GraphicRectangle : GraphicElement, IScalable, IRotatable
{
    private double width, height;
    private double rotation;
    
    public double Width => width;
    public double Height => height;
    public double Size => Math.Max(width, height);
    public double Rotation => rotation;
    
    public GraphicRectangle(double x, double y, double width, double height, string color = "黑色") 
        : base(x, y, color)
    {
        this.width = width > 0 ? width : throw new ArgumentException("宽度必须大于0");
        this.height = height > 0 ? height : throw new ArgumentException("高度必须大于0");
        this.rotation = 0;
    }
    
    public override void Draw()
    {
        if (isVisible)
        {
            Console.WriteLine($"绘制{color}矩形:位置({x:F1}, {y:F1}),大小{width:F1}x{height:F1},旋转{rotation:F1}°");
        }
    }
    
    // 实现IScalable接口
    public void Scale(double factor)
    {
        if (factor <= 0)
            throw new ArgumentException("缩放因子必须大于0");
            
        width *= factor;
        height *= factor;
        Console.WriteLine($"矩形缩放{factor}倍,新大小:{width:F1}x{height:F1}");
    }
    
    public void ScaleTo(double newSize)
    {
        if (newSize <= 0)
            throw new ArgumentException("新大小必须大于0");
            
        double factor = newSize / Math.Max(width, height);
        Scale(factor);
    }
    
    // 实现IRotatable接口
    public void Rotate(double angle)
    {
        rotation = (rotation + angle) % 360;
        if (rotation < 0) rotation += 360;
        Console.WriteLine($"矩形旋转{angle}°,当前角度:{rotation:F1}°");
    }
    
    public void RotateTo(double angle)
    {
        rotation = angle % 360;
        if (rotation < 0) rotation += 360;
        Console.WriteLine($"矩形旋转到:{rotation:F1}°");
    }
    
    public double CalculateArea()
    {
        return width * height;
    }
}

// 文本图形元素
public class GraphicText : GraphicElement, IScalable
{
    private string text;
    private double fontSize;
    
    public string Text => text;
    public double FontSize => fontSize;
    public double Size => fontSize;
    
    public GraphicText(double x, double y, string text, double fontSize = 12, string color = "黑色") 
        : base(x, y, color)
    {
        this.text = text ?? throw new ArgumentNullException(nameof(text));
        this.fontSize = fontSize > 0 ? fontSize : throw new ArgumentException("字体大小必须大于0");
    }
    
    public override void Draw()
    {
        if (isVisible)
        {
            Console.WriteLine($"绘制{color}文本:'{text}' 位置({x:F1}, {y:F1}),字体大小{fontSize:F1}");
        }
    }
    
    public void Scale(double factor)
    {
        if (factor <= 0)
            throw new ArgumentException("缩放因子必须大于0");
            
        fontSize *= factor;
        Console.WriteLine($"文本缩放{factor}倍,新字体大小:{fontSize:F1}");
    }
    
    public void ScaleTo(double newSize)
    {
        if (newSize <= 0)
            throw new ArgumentException("新大小必须大于0");
            
        fontSize = newSize;
        Console.WriteLine($"文本字体大小设置为:{fontSize:F1}");
    }
    
    public void SetText(string newText)
    {
        text = newText ?? throw new ArgumentNullException(nameof(newText));
        Console.WriteLine($"文本内容更新为:'{text}'");
    }
}

3.2 接口的高级特性

// 默认接口方法(C# 8.0+)
public interface IAdvancedDrawable : IDrawable
{
    // 默认实现
    void DrawWithEffect(string effect)
    {
        Console.WriteLine($"应用效果:{effect}");
        Draw();
    }
    
    // 静态方法
    static void PrintDrawingTips()
    {
        Console.WriteLine("绘图提示:使用合适的颜色和大小");
    }
    
    // 属性
    bool IsHighQuality { get; set; }
}

// 泛型接口
public interface IContainer<T>
{
    void Add(T item);
    bool Remove(T item);
    bool Contains(T item);
    int Count { get; }
    IEnumerable<T> Items { get; }
}

// 图形容器
public class GraphicContainer : IContainer<GraphicElement>, IDrawable
{
    private List<GraphicElement> elements;
    
    public int Count => elements.Count;
    public IEnumerable<GraphicElement> Items => elements.AsReadOnly();
    
    public GraphicContainer()
    {
        elements = new List<GraphicElement>();
    }
    
    public void Add(GraphicElement item)
    {
        if (item != null)
        {
            elements.Add(item);
            Console.WriteLine($"添加图形元素:{item.GetType().Name}");
        }
    }
    
    public bool Remove(GraphicElement item)
    {
        bool removed = elements.Remove(item);
        if (removed)
        {
            Console.WriteLine($"移除图形元素:{item.GetType().Name}");
        }
        return removed;
    }
    
    public bool Contains(GraphicElement item)
    {
        return elements.Contains(item);
    }
    
    public void Draw()
    {
        Console.WriteLine($"\n=== 绘制容器中的{Count}个图形元素 ===");
        foreach (var element in elements)
        {
            element.Draw();
        }
    }
    
    public void Erase()
    {
        Console.WriteLine("擦除容器中的所有图形元素");
        foreach (var element in elements)
        {
            element.Erase();
        }
    }
    
    public string GetDrawingInfo()
    {
        return $"图形容器包含{Count}个元素";
    }
    
    // 批量操作
    public void MoveAll(double deltaX, double deltaY)
    {
        Console.WriteLine($"\n批量移动所有元素 ({deltaX}, {deltaY})");
        foreach (var element in elements)
        {
            element.Move(deltaX, deltaY);
        }
    }
    
    public void ScaleAll(double factor)
    {
        Console.WriteLine($"\n批量缩放所有可缩放元素 {factor}倍");
        foreach (var element in elements)
        {
            if (element is IScalable scalable)
            {
                scalable.Scale(factor);
            }
        }
    }
    
    public void RotateAll(double angle)
    {
        Console.WriteLine($"\n批量旋转所有可旋转元素 {angle}°");
        foreach (var element in elements)
        {
            if (element is IRotatable rotatable)
            {
                rotatable.Rotate(angle);
            }
        }
    }
    
    public void Clear()
    {
        elements.Clear();
        Console.WriteLine("清空容器");
    }
}

3.3 接口使用示例

public class InterfaceDemo
{
    public static void Main()
    {
        Console.WriteLine("=== 接口演示 ===");
        
        // 创建图形元素
        var circle = new GraphicCircle(10, 20, 5, "红色");
        var rectangle = new GraphicRectangle(30, 40, 8, 6, "蓝色");
        var text = new GraphicText(50, 60, "Hello World", 14, "绿色");
        
        // 创建容器
        var container = new GraphicContainer();
        container.Add(circle);
        container.Add(rectangle);
        container.Add(text);
        
        // 绘制所有元素
        container.Draw();
        
        Console.WriteLine("\n=== 移动操作 ===");
        // 移动操作(所有元素都实现了IMovable)
        circle.Move(5, 5);
        rectangle.MoveTo(100, 100);
        
        Console.WriteLine("\n=== 缩放操作 ===");
        // 缩放操作(只有实现了IScalable的元素)
        circle.Scale(1.5);
        rectangle.ScaleTo(10);
        text.Scale(1.2);
        
        Console.WriteLine("\n=== 旋转操作 ===");
        // 旋转操作(只有实现了IRotatable的元素)
        if (rectangle is IRotatable rotatable)
        {
            rotatable.Rotate(45);
            rotatable.RotateTo(90);
        }
        
        Console.WriteLine("\n=== 批量操作 ===");
        // 批量操作
        container.MoveAll(10, 10);
        container.ScaleAll(0.8);
        container.RotateAll(30);
        
        Console.WriteLine("\n=== 接口类型检查 ===");
        // 接口类型检查和转换
        GraphicElement[] elements = { circle, rectangle, text };
        
        foreach (var element in elements)
        {
            Console.WriteLine($"\n{element.GetDrawingInfo()}");
            
            // 检查是否实现了特定接口
            if (element is IScalable scalable)
            {
                Console.WriteLine($"  可缩放,当前大小:{scalable.Size:F1}");
            }
            
            if (element is IRotatable rotatable2)
            {
                Console.WriteLine($"  可旋转,当前角度:{rotatable2.Rotation:F1}°");
            }
            
            // 使用模式匹配
            switch (element)
            {
                case GraphicCircle c:
                    Console.WriteLine($"  圆形面积:{c.CalculateArea():F2}");
                    break;
                case GraphicRectangle r:
                    Console.WriteLine($"  矩形面积:{r.CalculateArea():F2}");
                    break;
                case GraphicText t:
                    Console.WriteLine($"  文本内容:'{t.Text}'");
                    break;
            }
        }
        
        Console.WriteLine("\n=== 接口集合操作 ===");
        // 接口集合操作
        var drawables = new List<IDrawable> { circle, rectangle, text, container };
        var movables = elements.Cast<IMovable>().ToList();
        var scalables = elements.OfType<IScalable>().ToList();
        
        Console.WriteLine($"可绘制对象数量:{drawables.Count}");
        Console.WriteLine($"可移动对象数量:{movables.Count}");
        Console.WriteLine($"可缩放对象数量:{scalables.Count}");
        
        // 统一操作
        Console.WriteLine("\n统一绘制所有可绘制对象:");
        foreach (var drawable in drawables)
        {
            drawable.Draw();
        }
    }
}

4. 多态

4.1 多态的概念和实现

多态允许使用基类引用来调用派生类的方法,实现”一个接口,多种实现”。

// 媒体播放器示例
public abstract class MediaPlayer
{
    protected string fileName;
    protected TimeSpan duration;
    protected TimeSpan currentPosition;
    protected bool isPlaying;
    
    public string FileName => fileName;
    public TimeSpan Duration => duration;
    public TimeSpan CurrentPosition => currentPosition;
    public bool IsPlaying => isPlaying;
    
    protected MediaPlayer(string fileName)
    {
        this.fileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
        this.currentPosition = TimeSpan.Zero;
        this.isPlaying = false;
    }
    
    // 抽象方法 - 必须在派生类中实现
    public abstract void Play();
    public abstract void Pause();
    public abstract void Stop();
    public abstract string GetMediaInfo();
    
    // 虚方法 - 可以在派生类中重写
    public virtual void Seek(TimeSpan position)
    {
        if (position >= TimeSpan.Zero && position <= duration)
        {
            currentPosition = position;
            Console.WriteLine($"跳转到:{position:mm\\:ss}");
        }
        else
        {
            Console.WriteLine("无效的播放位置");
        }
    }
    
    public virtual void SetVolume(int volume)
    {
        volume = Math.Max(0, Math.Min(100, volume));
        Console.WriteLine($"音量设置为:{volume}%");
    }
    
    // 普通方法
    public void DisplayStatus()
    {
        Console.WriteLine($"文件:{fileName}");
        Console.WriteLine($"状态:{(isPlaying ? "播放中" : "已暂停")}");
        Console.WriteLine($"进度:{currentPosition:mm\\:ss} / {duration:mm\\:ss}");
        Console.WriteLine(GetMediaInfo());
    }
}

// 音频播放器
public class AudioPlayer : MediaPlayer
{
    private string artist;
    private string album;
    private int bitrate;
    
    public string Artist => artist;
    public string Album => album;
    public int Bitrate => bitrate;
    
    public AudioPlayer(string fileName, string artist, string album, TimeSpan duration, int bitrate = 320) 
        : base(fileName)
    {
        this.artist = artist;
        this.album = album;
        this.duration = duration;
        this.bitrate = bitrate;
    }
    
    public override void Play()
    {
        isPlaying = true;
        Console.WriteLine($"🎵 播放音频:{fileName} - {artist}");
    }
    
    public override void Pause()
    {
        isPlaying = false;
        Console.WriteLine($"⏸️ 暂停音频:{fileName}");
    }
    
    public override void Stop()
    {
        isPlaying = false;
        currentPosition = TimeSpan.Zero;
        Console.WriteLine($"⏹️ 停止音频:{fileName}");
    }
    
    public override string GetMediaInfo()
    {
        return $"音频 - 艺术家:{artist}, 专辑:{album}, 比特率:{bitrate}kbps";
    }
    
    // 音频特有的方法
    public void ShowLyrics()
    {
        Console.WriteLine($"显示 {fileName} 的歌词");
    }
    
    public void AddToPlaylist(string playlistName)
    {
        Console.WriteLine($"将 {fileName} 添加到播放列表:{playlistName}");
    }
}

// 视频播放器
public class VideoPlayer : MediaPlayer
{
    private string resolution;
    private int frameRate;
    private bool hasSubtitles;
    
    public string Resolution => resolution;
    public int FrameRate => frameRate;
    public bool HasSubtitles => hasSubtitles;
    
    public VideoPlayer(string fileName, string resolution, int frameRate, TimeSpan duration, bool hasSubtitles = false) 
        : base(fileName)
    {
        this.resolution = resolution;
        this.frameRate = frameRate;
        this.duration = duration;
        this.hasSubtitles = hasSubtitles;
    }
    
    public override void Play()
    {
        isPlaying = true;
        Console.WriteLine($"🎬 播放视频:{fileName} ({resolution})");
    }
    
    public override void Pause()
    {
        isPlaying = false;
        Console.WriteLine($"⏸️ 暂停视频:{fileName}");
    }
    
    public override void Stop()
    {
        isPlaying = false;
        currentPosition = TimeSpan.Zero;
        Console.WriteLine($"⏹️ 停止视频:{fileName}");
    }
    
    public override string GetMediaInfo()
    {
        return $"视频 - 分辨率:{resolution}, 帧率:{frameRate}fps, 字幕:{(hasSubtitles ? "有" : "无")}";
    }
    
    public override void Seek(TimeSpan position)
    {
        base.Seek(position);
        if (position >= TimeSpan.Zero && position <= duration)
        {
            Console.WriteLine("更新视频帧");
        }
    }
    
    // 视频特有的方法
    public void ToggleSubtitles()
    {
        hasSubtitles = !hasSubtitles;
        Console.WriteLine($"字幕:{(hasSubtitles ? "开启" : "关闭")}");
    }
    
    public void ChangeQuality(string newResolution)
    {
        resolution = newResolution;
        Console.WriteLine($"视频质量更改为:{resolution}");
    }
    
    public void TakeScreenshot()
    {
        Console.WriteLine($"截取 {fileName} 在 {currentPosition:mm\\:ss} 的截图");
    }
}

// 直播播放器
public class LiveStreamPlayer : MediaPlayer
{
    private string streamUrl;
    private int viewerCount;
    private bool isLive;
    
    public string StreamUrl => streamUrl;
    public int ViewerCount => viewerCount;
    public bool IsLive => isLive;
    
    public LiveStreamPlayer(string streamName, string streamUrl) : base(streamName)
    {
        this.streamUrl = streamUrl;
        this.duration = TimeSpan.MaxValue; // 直播没有固定时长
        this.viewerCount = 0;
        this.isLive = true;
    }
    
    public override void Play()
    {
        if (isLive)
        {
            isPlaying = true;
            viewerCount++;
            Console.WriteLine($"📺 连接直播:{fileName} (观众:{viewerCount})");
        }
        else
        {
            Console.WriteLine($"直播 {fileName} 已结束");
        }
    }
    
    public override void Pause()
    {
        Console.WriteLine("直播无法暂停,已断开连接");
        Stop();
    }
    
    public override void Stop()
    {
        isPlaying = false;
        if (viewerCount > 0) viewerCount--;
        Console.WriteLine($"📺 断开直播:{fileName} (观众:{viewerCount})");
    }
    
    public override void Seek(TimeSpan position)
    {
        Console.WriteLine("直播无法跳转到指定位置");
    }
    
    public override string GetMediaInfo()
    {
        return $"直播 - URL:{streamUrl}, 观众数:{viewerCount}, 状态:{(isLive ? "直播中" : "已结束")}";
    }
    
    // 直播特有的方法
    public void SendMessage(string message)
    {
        if (isPlaying)
        {
            Console.WriteLine($"💬 发送消息:{message}");
        }
        else
        {
            Console.WriteLine("未连接到直播,无法发送消息");
        }
    }
    
    public void EndStream()
    {
        isLive = false;
        isPlaying = false;
        Console.WriteLine($"直播 {fileName} 已结束");
    }
}

4.2 多态使用示例

public class PolymorphismDemo
{
    public static void Main()
    {
        Console.WriteLine("=== 多态演示 ===");
        
        // 创建不同类型的媒体播放器
        MediaPlayer[] players = {
            new AudioPlayer("song.mp3", "周杰伦", "叶惠美", TimeSpan.FromMinutes(4), 320),
            new VideoPlayer("movie.mp4", "1920x1080", 60, TimeSpan.FromHours(2), true),
            new LiveStreamPlayer("游戏直播", "https://live.example.com/stream1")
        };
        
        // 多态调用 - 同样的方法调用,不同的行为
        Console.WriteLine("\n=== 播放所有媒体 ===");
        foreach (MediaPlayer player in players)
        {
            Console.WriteLine($"\n--- {player.GetType().Name} ---");
            player.DisplayStatus();
            player.Play();
            player.SetVolume(75);
        }
        
        Console.WriteLine("\n=== 操作控制 ===");
        foreach (MediaPlayer player in players)
        {
            Console.WriteLine($"\n--- 控制 {player.FileName} ---");
            
            // 多态方法调用
            player.Seek(TimeSpan.FromMinutes(1));
            player.Pause();
            player.Play();
            
            // 类型特定的操作
            switch (player)
            {
                case AudioPlayer audio:
                    audio.ShowLyrics();
                    audio.AddToPlaylist("我的最爱");
                    break;
                    
                case VideoPlayer video:
                    video.ToggleSubtitles();
                    video.TakeScreenshot();
                    video.ChangeQuality("4K");
                    break;
                    
                case LiveStreamPlayer live:
                    live.SendMessage("Hello everyone!");
                    break;
            }
        }
        
        Console.WriteLine("\n=== 停止所有播放 ===");
        foreach (MediaPlayer player in players)
        {
            player.Stop();
        }
        
        // 演示运行时类型检查
        Console.WriteLine("\n=== 运行时类型检查 ===");
        DemonstrateTypeChecking(players);
        
        // 演示多态集合操作
        Console.WriteLine("\n=== 多态集合操作 ===");
        DemonstratePolymorphicOperations(players);
    }
    
    private static void DemonstrateTypeChecking(MediaPlayer[] players)
    {
        foreach (MediaPlayer player in players)
        {
            Console.WriteLine($"\n检查 {player.FileName}:");
            
            // is 操作符
            if (player is AudioPlayer)
            {
                Console.WriteLine("  这是音频播放器");
            }
            else if (player is VideoPlayer)
            {
                Console.WriteLine("  这是视频播放器");
            }
            else if (player is LiveStreamPlayer)
            {
                Console.WriteLine("  这是直播播放器");
            }
            
            // as 操作符
            AudioPlayer audioPlayer = player as AudioPlayer;
            if (audioPlayer != null)
            {
                Console.WriteLine($"  艺术家:{audioPlayer.Artist}");
            }
            
            // 模式匹配 (C# 7.0+)
            if (player is VideoPlayer { HasSubtitles: true } videoWithSubs)
            {
                Console.WriteLine($"  视频有字幕,分辨率:{videoWithSubs.Resolution}");
            }
            
            // typeof 和 GetType()
            Console.WriteLine($"  类型:{player.GetType().Name}");
            Console.WriteLine($"  是MediaPlayer?{player.GetType().IsSubclassOf(typeof(MediaPlayer))}");
        }
    }
    
    private static void DemonstratePolymorphicOperations(MediaPlayer[] players)
    {
        // 统计不同类型的播放器
        var typeCounts = players.GroupBy(p => p.GetType().Name)
                               .ToDictionary(g => g.Key, g => g.Count());
        
        Console.WriteLine("播放器类型统计:");
        foreach (var typeCount in typeCounts)
        {
            Console.WriteLine($"  {typeCount.Key}: {typeCount.Value}个");
        }
        
        // 筛选特定类型
        var audioPlayers = players.OfType<AudioPlayer>().ToList();
        var videoPlayers = players.OfType<VideoPlayer>().ToList();
        var liveStreamPlayers = players.OfType<LiveStreamPlayer>().ToList();
        
        Console.WriteLine($"\n音频播放器数量:{audioPlayers.Count}");
        Console.WriteLine($"视频播放器数量:{videoPlayers.Count}");
        Console.WriteLine($"直播播放器数量:{liveStreamPlayers.Count}");
        
        // 批量操作
        Console.WriteLine("\n批量设置音量为50%:");
        foreach (MediaPlayer player in players)
        {
            player.SetVolume(50);
        }
        
        // 条件操作
        Console.WriteLine("\n为所有视频启用字幕:");
        foreach (VideoPlayer video in videoPlayers)
        {
            if (!video.HasSubtitles)
            {
                video.ToggleSubtitles();
            }
        }
        
        // 计算总时长(排除直播)
        var totalDuration = players.Where(p => !(p is LiveStreamPlayer))
                                  .Sum(p => p.Duration.TotalMinutes);
        Console.WriteLine($"\n非直播内容总时长:{totalDuration:F1}分钟");
    }
}

5. 总结

本章深入介绍了继承和多态的核心概念:

  1. 继承基础:类的继承、方法重写、base关键字的使用
  2. 抽象类:抽象类和抽象方法的定义与实现
  3. 接口:接口的定义、实现和高级特性
  4. 多态:运行时类型确定、虚方法调用、类型检查和转换

关键要点: - 继承建立”is-a”关系,接口定义”can-do”能力 - 抽象类不能实例化,用于定义公共基础 - 接口支持多重实现,提供契约规范 - 多态实现”一个接口,多种实现” - 合理使用virtual、override、abstract关键字 - 运行时类型检查:is、as、typeof、GetType()

下一章预告: 下一章我们将学习异常处理,包括异常的捕获、处理和自定义异常类型。