本章目标
通过本章学习,你将掌握: - 继承的概念和实现 - 方法重写和虚方法 - 抽象类和抽象方法 - 接口的定义和实现 - 多态的概念和应用 - 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. 总结
本章深入介绍了继承和多态的核心概念:
- 继承基础:类的继承、方法重写、base关键字的使用
- 抽象类:抽象类和抽象方法的定义与实现
- 接口:接口的定义、实现和高级特性
- 多态:运行时类型确定、虚方法调用、类型检查和转换
关键要点: - 继承建立”is-a”关系,接口定义”can-do”能力 - 抽象类不能实例化,用于定义公共基础 - 接口支持多重实现,提供契约规范 - 多态实现”一个接口,多种实现” - 合理使用virtual、override、abstract关键字 - 运行时类型检查:is、as、typeof、GetType()
下一章预告: 下一章我们将学习异常处理,包括异常的捕获、处理和自定义异常类型。