引言
本文整理C#与.NET开发面试中高频出现的核心知识点,按「基础语法→面向对象→.NET核心→进阶特性→Web框架」逻辑划分,每个知识点标注核心考点和回答要点,适合面试前针对性复习。
一、C#基础语法(必问)
1.1 值类型 vs 引用类型
核心考点
存储位置、内存分配、核心区别及实际案例
回答要点
-
值类型(int/decimal/struct/枚举):存储在栈,复制时传递值,内存由系统自动释放,默认不可为null(需用 Nullable/int? 实现可空);
-
引用类型(string/object/数组/类):存储在堆,变量本身是堆内存地址(存于栈),复制时传递引用;
-
特殊说明:string 是引用类型但不可变(修改时新建字符串),且有字符串常量池优化;
-
面试真题示例:
-
int a=1; int b=a; b=2; 问a的值?(a=1,值类型传值)
-
Person p1=new Person(); Person p2=p1; p2.Name="张三"; 问p1.Name?(张三,引用类型传地址)
1.2 装箱(Boxing)与拆箱(Unboxing)
核心考点
定义、性能影响、避免方案
回答要点
-
装箱:值类型→引用类型(如 int i=1; object o=i;),堆上分配内存,存在性能损耗;
-
拆箱:引用类型→值类型(如 int j=(int)o;),需类型校验,性能略优于装箱;
-
避免方案:优先使用泛型(如 List 替代 ArrayList),杜绝不必要的类型转换。
1.3 空值处理(C# 6+ 高频)
核心考点
?.、??、??= 运算符用法,Nullable 应用
回答要点
-
?. 空条件运算符:避免 NullReferenceException(如 person?.Name,person为null时返回null);
-
?? 空合并运算符:null时返回备选值(如 name ?? "未知");
-
??= 空合并赋值:仅当变量为null时赋值(如 name ??= "默认");
-
Nullable/T?:值类型可空(如 int? age = null),通过 HasValue/Value 判断取值。
1.4 委托、事件、Lambda
核心考点
委托本质、事件与委托的关系、Lambda简化逻辑
回答要点
-
委托:类型安全的函数指针,可封装一个/多个方法(Action 无返回值、Func 有返回值);
-
事件:特殊委托(加 event 关键字),限制外部直接赋值,仅允许 +=/-=,实现发布-订阅模式;
-
Lambda:匿名函数简化写法(如 Func<int,int> add = x => x+1),编译后生成委托实例。
二、面向对象(OOP)核心
2.1 三大特性(封装、继承、多态)
核心考点
多态的实现方式
回答要点
-
封装:隐藏内部实现,暴露必要接口(如 private 字段 + public 属性);
-
继承:C# 仅支持单继承,通过 virtual(虚方法)+ override(重写)实现子类定制;
-
多态:同一行为不同表现,3种实现方式:
-
方法重写(virtual/override);
-
接口实现(不同类实现同一接口的不同逻辑);
-
抽象类(abstract):含抽象方法,必须被子类实现。
2.2 抽象类 vs 接口(面试必问)
| 对比维度 | 抽象类 | 接口 |
|---|---|---|
| 继承规则 | 单继承 | 多实现 |
| 成员类型 | 可包含抽象/非抽象成员 | 仅抽象成员(C#8+ 支持默认实现) |
| 构造函数 | 有 | 无 |
| 访问修饰符 | 可指定(public/private 等) | 默认 public(不可修改) |
| 使用场景 | 同类型类的共性复用 | 不同类型类的行为规范 |
核心总结
抽象类解决「是不是」的问题(如 Car 继承 Vehicle),接口解决「能不能」的问题(如 Car 实现 IRun)。
2.3 sealed 关键字
核心考点
用途及作用
回答要点
-
修饰类:密封类,禁止被继承(如 string 类);
-
修饰方法:密封方法,禁止子类重写(需配合 override 使用);
-
核心作用:防止子类篡改核心逻辑,助力 JIT 性能优化。
三、.NET 核心特性
3.1 .NET Framework vs .NET Core/.NET 5+
核心考点
跨平台能力、架构差异、性能对比
回答要点
-
.NET Framework:仅支持 Windows,重量级架构,依赖 IIS,版本耦合严重;
-
.NET Core/.NET 5+:跨平台(Windows/Linux/Mac),模块化设计(按需引用 NuGet 包),性能显著提升(优化 JIT、CoreCLR 运行时),支持独立部署(不依赖系统框架);
-
当前主流:.NET 6/8(LTS 长期支持版本,企业级项目优先选择)。
3.2 CLR 与 GC(垃圾回收)
核心考点
GC 回收机制、非托管资源释放方式
回答要点
-
CLR(公共语言运行时):.NET 核心组件,负责内存管理、JIT 编译(IL 转机器码)、异常处理;
-
GC(垃圾回收器):管理堆内存,采用「分代回收」机制(0/1/2 代):
-
0 代:短期小对象,回收最频繁;
-
1 代:过渡代,回收频率低;
-
2 代:长期大对象,回收频率最低;
-
大对象堆(LOH):存储 >85000 字节的对象,不参与代回收,回收成本高;
-
回收时机:内存不足时自动触发,不推荐手动调用 GC.Collect();
-
非托管资源(文件流/数据库连接)释放:
-
实现 IDisposable 接口,配合 using 语句(自动调用 Dispose 方法);
-
析构函数(~类名):作为兜底方案,由 GC 触发。
3.3 依赖注入(DI).NET Core 内置
核心考点
核心思想、生命周期、使用注意事项
回答要点
-
核心思想:控制反转(IOC),解耦依赖关系,便于单元测试;
-
3 种生命周期(面试高频):
-
瞬时(Transient):每次获取时新建实例;
-
作用域(Scoped):同一请求/作用域内实例唯一(Web 项目中对应一个 HTTP 请求);
-
单例(Singleton):应用生命周期内全局唯一实例;
-
关键注意:Scoped 服务不能注入到 Singleton 服务中(生命周期不匹配,会导致对象释放异常)。
四、集合与泛型
4.1 泛型的优点
核心考点
类型安全、性能优势、代码复用
回答要点
-
类型安全:编译时校验类型,避免运行时类型转换错误;
-
高性能:避免装箱/拆箱操作(如 List 对比 ArrayList);
-
代码复用:一套泛型代码适配多种数据类型(如 List 可存储 int/string/自定义类)。
4.2 常用集合对比
| 集合类型 | 核心特点 | 适用场景 |
|---|---|---|
| List | 动态数组,随机访问快,增删尾部高效、中间低效 | 读多写少、按索引访问的场景 |
| HashSet | 无重复元素,哈希表实现,查找效率 O(1) | 去重、判断元素是否存在 |
| Dictionary<TK,TV> | 动态数组,随机访问快,增删尾部高效、中间低效 | 按键快速查询、数据映射 |
| Queue | 先进先出(FIFO) | 任务排队、消息队列 |
| Stack | 后进先出(LIFO) | 栈操作、撤销功能 |
五、多线程与异步编程
5.1 Thread vs Task
核心考点
轻量性、线程池依赖、使用场景
回答要点
-
Thread:重量级线程,手动管理生命周期,创建/销毁成本高,直接占用系统线程;
-
Task(.NET 4.0+):基于线程池的轻量级任务,支持异步等待(await),可组合(Task.WhenAll/WhenAny),资源利用率更高;
-
最佳实践:优先使用 Task,避免直接操作 Thread。
5.2 async/await(面试高频)
核心考点
原理、使用规范、常见坑
回答要点
-
核心价值:异步不阻塞调用线程(如 Web 项目中释放线程处理其他请求),提升系统并发能力;
-
实现原理:编译后生成状态机,await 处暂停执行,异步操作完成后恢复上下文继续执行;
-
使用注意:
-
async 方法返回值:优先用 Task/Task(可捕获异常、支持等待),void 仅用于事件处理(无法捕获异常);
-
避免「异步同步化」:不要在 async 方法中调用 Task.Wait()/Result,会导致线程阻塞甚至死锁。
5.3 线程安全
核心考点
锁机制、死锁避免方案
回答要点
-
常用锁机制:
-
lock 语句:本质是 Monitor.Enter/Exit 的封装,推荐锁定 private readonly object _lockObj = new object()(避免锁定公共对象);
-
并发集合:ConcurrentDictionary/ConcurrentQueue 等,内置线程安全机制,无需手动加锁;
-
死锁产生条件:互斥、持有并等待、不可剥夺、循环等待;
-
死锁避免:按固定顺序加锁、设置锁超时(Monitor.TryEnter)、避免嵌套锁。
六、ASP.NET Core 核心(Web 方向必问)
6.1 中间件(Middleware)
核心考点
管道模型、Use/Run/Map 方法区别
回答要点
-
核心概念:请求处理管道由一系列中间件组成,每个中间件负责一个特定功能(认证、日志、路由、静态文件等);
-
关键方法:
-
Use:执行自身逻辑后调用下一个中间件(next());
-
Run:执行逻辑后终止管道(无 next 调用);
-
Map:按请求路径分支管道(如 Map("/api", app => { ... }) 处理 API 路径请求);
-
自定义中间件:实现 InvokeAsync 方法,通过 app.UseMiddleware<自定义中间件>() 注册。
6.2 配置系统
核心考点
配置源、优先级顺序
回答要点
-
常见配置源(优先级从高到低):命令行参数 > 环境变量 > appsettings.{环境}.json(如 appsettings.Production.json)> appsettings.json > 内存配置;
-
读取方式:通过 IConfiguration 接口注入读取,或通过 Bind/Get 绑定到强类型类(推荐,类型安全)。
6.3 过滤器(Filter)
核心考点
过滤器类型、执行顺序
回答要点
-
5 种核心过滤器:
-
授权过滤器(AuthorizationFilter):最先执行,负责权限校验;
-
资源过滤器(ResourceFilter):授权后执行,可实现缓存、请求预处理;
-
动作过滤器(ActionFilter):Action 方法执行前后触发;
-
结果过滤器(ResultFilter):Action 结果返回前后触发;
-
异常过滤器(ExceptionFilter):捕获全局未处理异常;
-
执行顺序:授权过滤器 → 资源过滤器 → 动作过滤器 → 动作方法 → 结果过滤器 → 响应;异常时触发异常过滤器。
七、其他高频考点
7.1 设计模式(常问单例、工厂)
单例模式(线程安全实现)
csharp
// 懒汉式(推荐,Lazy<T> 自带线程安全)
public class Singleton
{
// 私有构造函数,禁止外部实例化
private Singleton() { }
// Lazy<T> 延迟初始化,默认线程安全
private static readonly Lazy<Singleton> _instance = new Lazy<Singleton>(() => new Singleton());
// 全局访问点
public static Singleton Instance => _instance.Value;
}
工厂模式
核心思想:封装对象创建逻辑,解耦对象创建与使用(简单工厂/工厂方法/抽象工厂,根据复杂度选择)。
7.2 LINQ
核心考点
延迟执行、查询语法 vs 方法语法
回答要点
-
延迟执行:LINQ 查询不会立即执行,直到遍历(foreach)、调用 ToList()/Count() 等方法时才触发;
-
两种语法:
-
查询语法:from x in list where x > 10 select x(接近 SQL,易读);
-
方法语法:list.Where(x => x > 10)(链式调用,灵活度高);
-
本质:两种语法最终都会编译为相同的方法调用。
7.3 异常处理
核心考点
throw vs throw ex 区别、最佳实践
回答要点
-
throw:抛出原始异常,保留完整堆栈信息(便于定位问题);
-
throw ex:重置异常堆栈,丢失原始异常发生位置(不推荐);
-
最佳实践:
-
捕获异常后如需重新抛出,使用 throw;
-
自定义异常继承 Exception 类,添加业务相关属性(如 ErrorCode);
-
避免捕获所有异常(catch (Exception)),按需捕获特定异常。
面试总结
-
基础层:值类型/引用类型、装箱拆箱、空值处理是 C# 基础必问,需结合内存分配逻辑回答;
-
核心层:抽象类 vs 接口、GC 回收机制、async/await 原理、DI 生命周期是高频难点,需结合实际项目场景说明;
-
框架层:ASP.NET Core 中间件、配置系统、过滤器是 Web 方向核心,需理解管道模型和执行逻辑。