抽象类 #

一、抽象类概述 #

抽象类是不能被实例化的类,用于定义子类的通用模板。

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