抽象类 #
一、抽象类概述 #
抽象类是不能被实例化的类,用于定义子类的通用模板。
1.1 抽象类特点 #
- 不能实例化
- 可以包含抽象成员和非抽象成员
- 可以有构造方法
- 可以有访问修饰符
- 子类必须实现所有抽象成员
1.2 基本语法 #
csharp
public abstract class Animal
{
public string Name { get; set; }
public abstract void MakeSound();
public void Sleep()
{
Console.WriteLine($"{Name}正在睡觉");
}
}
二、抽象方法 #
2.1 定义抽象方法 #
csharp
public abstract class Shape
{
public abstract double Area { get; }
public abstract double Perimeter { get; }
public abstract void Draw();
}
2.2 实现抽象方法 #
csharp
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double Area => Width * Height;
public override double Perimeter => 2 * (Width + Height);
public override void Draw()
{
Console.WriteLine($"绘制矩形 {Width}x{Height}");
}
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double Area => Math.PI * Radius * Radius;
public override double Perimeter => 2 * Math.PI * Radius;
public override void Draw()
{
Console.WriteLine($"绘制圆形 半径{Radius}");
}
}
2.3 抽象属性 #
csharp
public abstract class Person
{
public abstract string Name { get; set; }
public abstract int Age { get; }
}
public class Student : Person
{
private string _name;
private int _age;
public override string Name
{
get => _name;
set => _name = value;
}
public override int Age => _age;
public Student(string name, int age)
{
_name = name;
_age = age;
}
}
三、抽象类与继承 #
3.1 多层继承 #
csharp
public abstract class Animal
{
public string Name { get; set; }
public abstract void MakeSound();
public void Sleep()
{
Console.WriteLine($"{Name}正在睡觉");
}
}
public abstract class Mammal : Animal
{
public abstract void GiveBirth();
public void Nurse()
{
Console.WriteLine($"{Name}正在哺乳");
}
}
public class Dog : Mammal
{
public override void MakeSound()
{
Console.WriteLine("汪汪汪");
}
public override void GiveBirth()
{
Console.WriteLine("狗生小狗");
}
}
3.2 部分实现 #
csharp
public abstract class Vehicle
{
public string Brand { get; set; }
public abstract void Start();
public abstract void Stop();
public abstract int Wheels { get; }
public void Honk()
{
Console.WriteLine("鸣笛");
}
}
public abstract class Car : Vehicle
{
public override int Wheels => 4;
public override void Start()
{
Console.WriteLine("启动汽车");
}
}
public class Sedan : Car
{
public override void Stop()
{
Console.WriteLine("停止轿车");
}
}
四、抽象类构造方法 #
4.1 定义构造方法 #
csharp
public abstract class Animal
{
public string Name { get; }
public int Age { get; }
protected Animal(string name, int age)
{
Name = name;
Age = age;
}
public abstract void MakeSound();
}
public class Dog : Animal
{
public string Breed { get; }
public Dog(string name, int age, string breed) : base(name, age)
{
Breed = breed;
}
public override void MakeSound()
{
Console.WriteLine("汪汪汪");
}
}
4.2 构造方法调用链 #
csharp
public abstract class BaseEntity
{
public int Id { get; }
public DateTime CreatedAt { get; }
protected BaseEntity()
{
CreatedAt = DateTime.Now;
}
protected BaseEntity(int id) : this()
{
Id = id;
}
}
public class User : BaseEntity
{
public string Name { get; set; }
public User() { }
public User(int id, string name) : base(id)
{
Name = name;
}
}
五、抽象类vs接口 #
5.1 对比 #
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 实例化 | 不能 | 不能 |
| 构造方法 | 可以有 | 不能有 |
| 字段 | 可以有 | 不能有 |
| 实现成员 | 可以有 | C# 8+可以有默认实现 |
| 多继承 | 单继承 | 可实现多个 |
| 访问修饰符 | 可以有 | 默认public |
5.2 选择建议 #
使用抽象类:
- 有共享代码
- 需要字段
- 需要构造方法
- 有访问修饰符需求
使用接口:
- 需要多继承
- 定义行为契约
- 不需要共享实现
5.3 组合使用 #
csharp
public interface IDrawable
{
void Draw();
}
public interface IResizable
{
void Resize(double factor);
}
public abstract class Shape : IDrawable, IResizable
{
public abstract double Area { get; }
public abstract void Draw();
public virtual void Resize(double factor)
{
Console.WriteLine($"缩放{factor}倍");
}
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double Area => Width * Height;
public override void Draw()
{
Console.WriteLine($"绘制矩形 {Width}x{Height}");
}
public override void Resize(double factor)
{
Width *= factor;
Height *= factor;
}
}
六、实战示例 #
6.1 数据访问层 #
csharp
public abstract class Repository<T> where T : class
{
protected readonly DbContext _context;
protected Repository(DbContext context)
{
_context = context;
}
public abstract T GetById(int id);
public abstract IEnumerable<T> GetAll();
public abstract void Add(T entity);
public abstract void Update(T entity);
public abstract void Delete(int id);
public void Save()
{
_context.SaveChanges();
}
}
public class UserRepository : Repository<User>
{
public UserRepository(DbContext context) : base(context) { }
public override User GetById(int id)
{
return _context.Set<User>().Find(id);
}
public override IEnumerable<User> GetAll()
{
return _context.Set<User>().ToList();
}
public override void Add(User entity)
{
_context.Set<User>().Add(entity);
}
public override void Update(User entity)
{
_context.Set<User>().Update(entity);
}
public override void Delete(int id)
{
var user = GetById(id);
if (user != null)
_context.Set<User>().Remove(user);
}
}
6.2 日志系统 #
csharp
public abstract class Logger
{
public LogLevel MinimumLevel { get; set; } = LogLevel.Info;
public void Log(LogLevel level, string message)
{
if (level < MinimumLevel) return;
var formattedMessage = FormatMessage(level, message);
WriteLog(level, formattedMessage);
}
protected virtual string FormatMessage(LogLevel level, string message)
{
return $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {message}";
}
protected abstract void WriteLog(LogLevel level, string message);
}
public class ConsoleLogger : Logger
{
protected override void WriteLog(LogLevel level, string message)
{
var originalColor = Console.ForegroundColor;
Console.ForegroundColor = level switch
{
LogLevel.Error => ConsoleColor.Red,
LogLevel.Warning => ConsoleColor.Yellow,
_ => ConsoleColor.White
};
Console.WriteLine(message);
Console.ForegroundColor = originalColor;
}
}
public class FileLogger : Logger
{
private readonly string _filePath;
public FileLogger(string filePath)
{
_filePath = filePath;
}
protected override void WriteLog(LogLevel level, string message)
{
File.AppendAllText(_filePath, message + Environment.NewLine);
}
}
public enum LogLevel { Debug, Info, Warning, Error }
七、总结 #
抽象类要点:
| 要点 | 说明 |
|---|---|
| abstract关键字 | 定义抽象类/方法 |
| 不能实例化 | 只能被继承 |
| 抽象方法 | 子类必须实现 |
| 可以有实现 | 包含具体方法 |
| 构造方法 | 可以定义 |
下一步,让我们学习接口!
最后更新:2026-03-26