C#抽象类&接口 项目实操选型清单(开发直接对照)
一、快速判定5条规则(遇到场景直接选)
✅ 选【抽象类 abstract】满足任意一条
- 多个子类共用字段/成员变量(Id、Name、公共缓存、连接对象等)
- 多个子类有大量重复业务代码,只想部分方法由子类重写
- 需要通过构造函数统一初始化子类公共数据
- 业务是
is-a从属关系:XX是一种XX(货车→车辆、MySQLDao→BaseDao) - 需要使用
private/protected封装内部私有逻辑
✅ 选【接口 interface】满足任意一条
- 类需要具备多个互不相关的功能(多能力组合,C#单继承做不到)
- 只定义行为规范,没有公共属性、没有共享数据(契约定义)
- 无关业务类需要统一行为标准(文件、网络、数据库都要释放资源→IDisposable)
- 分层架构、依赖注入、单元测试Mock(Service层依赖IXXXService)
- 插件化、可替换实现类(随时切换Sql实现、Redis实现)
二、项目常用组合方案(工业级标准写法:接口+抽象类)
接口:定义对外契约;抽象类:实现接口+封装公共代码;实体类:继承抽象类
//1.接口:对外约束规范
public interface IUserRepository
{User GetById(int id);bool Add(User user);
}
//2.抽象类:实现接口,封装公共逻辑
public abstract class BaseUserRepo : IUserRepository
{protected DbContext _db; //公共字段,所有子类复用protected BaseUserRepo(DbContext db) => _db = db;//公共通用实现public virtual bool Add(User user){_db.Add(user);return _db.SaveChanges()>0;}//抽象方法由不同数据库实现public abstract User GetById(int id);
}
//3.具体实现
public class SqlUserRepo : BaseUserRepo
{public SqlUserRepo(DbContext db):base(db){}public override User GetById(int id){return _db.Users.Find(id);}
}
适用场景:仓储层、服务层通用架构
三、避坑黑名单(这些场景严禁乱用)
禁止用抽象类的场景
- 只为给类加一个附加功能(如可排序、可导出)→改用接口
- 后期需要更换多种实现、插件扩展→优先接口
原因:抽象类单继承,一旦继承占用,无法再继承别的基类
禁止全用接口的场景
- 十几个实现类都有一模一样的属性(CreateTime、Creator)→抽抽象类存字段
- 大量重复的工具逻辑,每个实现类重复写→抽象类封装公共方法
原因:接口无字段,所有实现类重复代码,维护成本暴增
四、版本兼容选型(C#版本区分)
- .NET Framework / C#7.3及以下
接口尽量少新增方法,新增必改全部实现类;通用公共逻辑一律抽象类。 - .NET Core3.1+ / C#8.0+
接口可用默认实现新增方法,不需要改动实现类,部分通用逻辑可下沉到接口。
五、业务场景对照表
| 业务场景 | 选型方案 |
|---|---|
| 各种数据库Dao(Mysql/Oracle/SqlServer) | 接口IRepository + 抽象BaseRepository + 具体实现类 |
| 工具能力:导出Excel、打印、排序 | 单独接口 IExport、IPrint、ISort |
| 不同类型支付(微信/支付宝) | IPay接口 + BasePay抽象类封装公共签名逻辑 |
| 框架规范:释放资源、比较大小 | 纯接口(IDisposable、IComparable) |
六、一句话总结口诀
契约解耦用接口,共有状态抽象类;
多能组合上接口,从属继承抽象类;
大型项目最优解,接口定规范,抽象做复用。
