c# 面试题及答案 2026

来源:这里教程网 时间:2026-02-21 17:42:07 作者:

C# 面试题没有标准“2026 年版”答案——面试官真正看的不是你背过多少题,而是你能否在具体场景中识别问题、权衡取舍、写出可维护的代码。下面挑几个高频但容易答偏的点,直击实操细节。

为什么
string
是引用类型却表现得像值类型?

这不是“表现像”,而是编译器和运行时共同做了两件事:

string
不可变(immutable),且重载了
==
运算符。所以
str1 == str2
默认比较内容而非引用。

错误认知:以为
string
是值类型 → 实际它继承自
object
,分配在堆上,
typeof(string).IsClass
返回
true
坑点:用
ReferenceEquals(str1, str2)
判断字符串相等会出错,尤其在字符串驻留(interning)后,相同字面量可能指向同一对象,但逻辑上不该依赖这个行为
正确做法:内容比较用
string.Equals(a, b, StringComparison.Ordinal)
;明确需要引用比较时才用
ReferenceEquals

IEnumerable<t></t>
延迟执行导致的常见内存/性能陷阱

很多人知道“延迟执行”,但没意识到多次遍历

IEnumerable<t></t>
可能重复触发耗时操作(如数据库查询、文件读取、HTTP 调用)。

典型错误:把 LINQ 查询结果直接赋给字段或传给多个方法,每次调用
Count()
ToList()
foreach
都重新执行源逻辑
修复方式:按需选择缓存策略 —— 确定数据小且不变,用
.ToList()
;需流式处理且只遍历一次,保持
IEnumerable<t></t>
;若需多次遍历又怕重复计算,考虑
IReadOnlyList<t></t>
或显式缓存
示例:
var query = dbContext.Users.Where(u => u.IsActive); // IQueryable<User>,延迟执行
Console.WriteLine(query.Count()); // 触发 SQL COUNT(*)
Console.WriteLine(query.ToList().Count); // 再次触发 SELECT *,全量拉取!

async/await
Task.Run
的滥用场景

不是所有“想异步”的地方都该加

Task.Run
。它本质是把同步工作扔进线程池,**不能让 CPU 密集型操作变快,反而增加调度开销**。

适合用:CPU 密集 + 必须不阻塞 UI/请求线程(如 WinForms 渲染线程、ASP.NET Core 同步上下文敏感场景) 不该用: 已存在原生异步 API 的场景(如
HttpClient.GetAsync
FileStream.ReadAsync
)→ 直接 await
在 ASP.NET Core 中对普通业务逻辑包裹
Task.Run
→ 抢占线程池资源,降低吞吐量
替代思路:I/O 操作优先走 async API;CPU 密集型任务若真必须后台跑,评估是否该拆到后台服务或队列中处理

为什么
record
类的
with
表达式不能修改
init
属性以外的字段?

with
是语法糖,底层调用的是生成的
Clone()
+ 属性赋值。它只作用于
init
set
可写的属性,而
record
的主构造参数默认生成
init
属性。

常见误解:“
with
就是深拷贝” → 实际是浅拷贝,且仅对可写属性生效;若字段是
private set
或只有
get
with
无法修改
验证方式:反编译看生成的
<clone>$</clone>
方法,它只复制声明为
init
set
的成员
如果需要定制复制逻辑(比如忽略某字段、转换值),应显式重写
Clone()
或使用
record struct
+ 手动构造

真正卡人的从来不是概念定义,而是你在改一段遗留代码时,突然发现

IEnumerable
被反复枚举了七次,或者
async
方法里嵌了三层
Task.Run
还配了
.Result
—— 那些地方,文档不会标红,但线上会报错。

相关推荐