主题
yhwl-高级研发&架构师笔试胆
请解释 Attribute 和 Property 有何区别?并举例说明两者的应用场景。
解答
- 本质区别
Property(属性):属于类的成员,用于描述对象的状态/数据,存储运行时的值;Attribute(特性):是元数据,用于给类/方法/属性附加标记信息,不存储业务数据,仅用于编译/运行时识别。
- 语法与用途
Property:通过get/set访问,用于封装字段,提供数据读写能力;Attribute:继承自Attribute类,使用[]标记,配合反射读取使用。
- 应用场景
Property:存储对象数据,如User类的Name、Age;Attribute:标记验证、序列化、ORM映射,如[Required]、[JsonPropertyName]、[Key]。
- 代码示例
csharp
// Property:存储数据
public class User
{
public string Name { get; set; }
}
// Attribute:元数据标记
public class User
{
[Required] // 非空验证特性
public string Name { get; set; }
}请解释 List、Dictionary、Collection 及 IList、IDictionary、ICollection 有何区别?分别用于什么场景?
解答
- 接口与实现类的关系
IList/IDictionary/ICollection:接口,定义集合规范,无具体实现;List/Dictionary/Collection:具体实现类,基于接口实现完整功能。
- 逐个说明
ICollection:所有非泛型/泛型集合的基础接口,定义Count、Add、Remove、Clear、遍历等核心能力;IList:继承ICollection,有序集合接口,支持索引访问、插入、删除指定位置元素;IDictionary:继承ICollection,键值对集合接口,要求键唯一,支持按键快速查找。List<T>:IList<T>的动态数组实现,有序、支持索引、查询快; 场景:需要有序列表、频繁按索引读取数据。Dictionary<TKey,TValue>:IDictionary<TKey,TValue>的哈希表实现,按键O(1)查找; 场景:需要键值映射、快速查找、唯一键标识。Collection<T>:IList<T>的封装类,可重写插入/删除逻辑,常用于自定义集合; 场景:需要扩展集合行为(如拦截添加操作)。
- 最佳实践
- 方法参数/返回值优先用接口(
IList/IDictionary),实现解耦; - 内部实例化使用具体类(
List/Dictionary),保证功能与性能。
列举你熟悉的 ORM 框架,并对比说明它们的优缺点。
解答
Entity Framework Core(EF Core)
- 优点:功能完整、
LINQ查询、自动映射、多数据库支持、原生适配.NET、易于开发; - 缺点:复杂查询生成
SQL效率一般、性能弱于轻量级ORM; - 场景:企业项目、快速开发、复杂业务系统。
Dapper
- 优点:性能极高、轻量、手写
SQL、灵活可控; - 缺点:无自动迁移、无动态查询、需手动管理
SQL; - 场景:高性能要求、复杂
SQL、性能敏感业务。
SqlSugar
- 优点:国产、易用、高性能、支持分库分表、读写分离、自动迁移;
- 缺点:生态小于
EF Core; - 场景:.NET全平台、高并发、中小项目快速开发。
FreeSql
- 优点:极简语法、多数据库、CodeFirst、性能优秀;
- 场景:快速开发、跨库项目。
什么是 IOC?什么是 AOP?解释其实现原理,列举你熟悉的 IOC 及 AOP 框架。
解答
IOC(控制反转)
- 定义:将对象创建、依赖管理的控制权从业务代码交给容器;
- 核心:依赖注入(
DI),容器自动注入依赖对象; - 原理:反射+配置+生命周期管理;
- 框架:
Microsoft.Extensions.DependencyInjection(.NET原生)、Autofac。
AOP(面向切面编程)
- 定义:不修改业务代码,横向添加通用逻辑(日志、事务、缓存、验证);
- 原理:动态代理(运行时生成代理类,在方法前后织入逻辑);
- 框架:
AspectCore、Castle DynamicProxy、PostSharp。
- 一句话总结
IOC:管对象生命周期与依赖;AOP:管横向通用逻辑增强。
列举 Asp.net Mvc HttpApplication 中常用的事件,并描述它们发生的时间及作用。
解答
BeginRequest
- 时机:请求开始第一个事件;
- 作用:请求初始化、全局预处理。
AuthenticateRequest
- 时机:身份验证触发;
- 作用:自定义用户身份校验。
AuthorizeRequest
- 时机:身份验证后;
- 作用:授权校验、权限判断。
ResolveRequestCache
- 时机:尝试从缓存读取响应;
- 作用:缓存命中直接返回,提升性能。
AcquireRequestState
- 时机:获取
Session状态; - 作用:读取/写入会话数据。
PreRequestHandlerExecute
- 时机:进入控制器/处理程序前;
- 作用:请求最终预处理。
PostRequestHandlerExecute
- 时机:处理程序执行完毕;
- 作用:执行后处理、清理。
EndRequest
- 时机:请求完全结束;
- 作用:最终收尾、日志记录、资源释放。
Asp.net core 相对与 asp.net 的优势。Asp.net core 配置可以通过哪几种方式设置?
解答
一、优势
- 跨平台:支持
Windows/Linux/macOS; - 高性能:
Kestrel服务器、管道优化、高并发更强; - 模块化:基于
NuGet按需引用,体积更小; - 原生
DI:内置IOC容器,解耦更方便; - 统一
MVC/WebAPI:架构更简洁; - 开源社区活跃:持续更新迭代。
二、配置方式
appsettings.json:默认配置文件;- 环境变量:部署环境差异化配置;
- 命令行参数:启动时覆盖配置;
User Secrets:开发环境敏感配置;- 内存配置:程序内动态配置;
- 自定义提供程序:数据库/远程配置中心。
举例说明 Asp.net core中常用的中间件。Startup类中Configure 和ConfigureServices 方法的作用分别是什么?
解答
一、常用中间件
UseRouting:启用路由匹配;UseEndpoints:配置请求终结点;UseAuthentication:身份验证;UseAuthorization:权限授权;UseStaticFiles:静态文件访问;UseCors:跨域配置;UseExceptionHandler:全局异常处理。
二、方法作用
ConfigureServices
- 负责注册服务到
IOC容器; - 如:注入
DbContext、配置跨域、注册业务服务。
Configure
- 负责构建请求管道;
- 按顺序注册中间件,定义请求处理流程。
REST/webApi服务安全访问措施有哪些?如何优化数据传输的性能?
解答
一、安全访问措施
HTTPS加密:防止传输窃听、篡改;- 身份验证:
JWT、OAuth2.0、Token; - 授权控制:
RBAC角色权限、接口鉴权; - 请求限流:防暴力攻击;
CSRF防护:验证请求来源;- 参数校验:防
SQL注入、XSS攻击; - 敏感信息脱敏。
二、性能优化
- 数据压缩:
Gzip压缩响应体; - 分页/只查需要字段:减少传输量;
- 缓存:本地缓存、
Redis缓存、响应缓存; - 异步接口:提升并发能力;
CDN加速:静态资源分发;- 高效序列化:使用
System.Text.Json/Protobuf; - 避免过度嵌套:精简返回结构。
线程安全是指的什么?该应该如何处理此问题?
解答
线程安全定义 多线程同时访问共享资源时,不会出现数据错乱、逻辑异常,保证结果正确。
解决方案
lock锁:保护临界区,同一时间只允许一个线程访问;- 原子类:
Interlocked实现原子操作,无锁更高效; - 线程安全集合:
ConcurrentQueue、ConcurrentDictionary; - 只读/不可变对象:无修改则无线程安全问题;
- 异步
Task:合理使用异步,减少锁竞争; - 分布式锁:多实例服务使用
Redis/ZooKeeper锁。
- 核心原则 最小化锁范围、避免嵌套锁、优先使用无锁方案。
你熟悉的单元测试框架有哪些?如何编写单元测试?
解答
一、.NET常用单元测试框架
xUnit:.NET主流、简洁、支持并行测试;NUnit:跨平台、生态成熟;MSTest:微软官方、适配Visual Studio。
二、单元测试编写步骤
- 引用框架:安装
xUnit+xUnit.runner.visualstudio; - 创建测试类:命名规范
[被测类]Tests; - 编写测试方法:给定条件→执行方法→断言结果;
- 运行测试:查看通过/失败。
三、示例
csharp
public class Calculator
{
public int Add(int a, int b) => a + b;
}
public class CalculatorTests
{
[Fact]
public void Add_TwoNumbers_ReturnsCorrectSum()
{
var calc = new Calculator();
var result = calc.Add(2, 3);
Assert.Equal(5, result);
}
}请谈谈设计模式的几大原则,并列举你用过的设计模式和相关类库。
解答
一、设计模式七大原则
- 单一职责:一个类只做一件事;
- 开闭原则:对扩展开放,对修改关闭;
- 里氏替换:子类可无缝替换父类;
- 依赖倒置:依赖抽象,不依赖具体实现;
- 接口隔离:接口精简,不强迫实现无用方法;
- 迪米特法则:最少知道原则,减少类耦合;
- 合成复用:优先组合/聚合,少用继承。
二、常用设计模式
- 单例模式:
Singleton,全局唯一实例; - 工厂模式:
Factory,封装对象创建; - 观察者模式:事件/委托/消息队列;
- 策略模式:封装算法,可互换;
- 适配器模式:兼容不兼容接口;
- 装饰器模式:动态增强功能;
- 仓储模式:
Repository,数据访问层封装。
什么是领域驱动设计?如何进行领域建模?举例说明领域驱动设计中的相关名词
解答
一、DDD(领域驱动设计) 以业务领域为核心,通过统一语言、模型驱动,将复杂业务逻辑转化为高质量代码。
二、领域建模步骤
- 梳理业务,划分限界上下文;
- 识别实体、值对象、聚合;
- 定义聚合根;
- 设计领域服务、领域事件、仓储。
三、核心概念(含代码示例)
- 实体:有唯一标识,如
Order; - 值对象:无唯一标识,不可变,如
Address; - 聚合:一组相关对象的集合,统一管理;
- 聚合根:聚合入口,如
Order是聚合根; - 仓储
Repository:领域对象持久化; - 领域服务:处理跨实体业务逻辑;
- 领域事件:领域状态变更通知。
口述设计一个分布式任务执行系统。
解答
一、核心目标 高可用、负载均衡、无冲突、可扩展、故障自动转移。
二、架构设计
- 任务存储:
MySQL持久化任务、状态、执行日志; - 调度中心:负责扫描、触发、分配任务;
- 执行节点:多实例部署,执行具体任务;
- 分布式锁:
Redis锁,防止多节点重复执行; - 消息队列:任务异步排队、削峰、解耦。
三、关键问题解决
- 冲突避免:任务加分布式锁,抢到锁才能执行;
- 任务排队:按优先级进入
MQ,调度器消费; - 持久化:任务信息、执行结果全量入库;
- 故障转移:心跳检测,宕机任务标记未完成,自动重分配;
- 横向扩展:无状态执行节点,直接扩容实例;
- 不停机扩缩容:滚动更新,新节点上线自动参与调度。
四、核心保证 最终一致性、不重复执行、不丢失任务、高可用。
基于容器化技术设计微服务架构,解决出库订单库存扣减并发问题
解答
一、架构目标 解决并发超卖,支持CI/CD、弹性伸缩、可监控。
二、微服务划分
- 订单服务:创建订单、发送扣减消息;
- 库存服务:原子扣减库存、幂等校验;
- 消息队列:
RabbitMQ异步削峰、解耦; - 数据库:库存加行锁/乐观锁;
- 网关:统一入口、限流、鉴权;
- 容器平台:
Docker+K8s; - 监控:
Prometheus+Grafana。
三、并发扣减方案
- 乐观锁:库存表加
Version字段,CAS更新; - 分布式锁:扣减前加
Redis锁; - 消息队列串行化:同一商品库存扣减串行执行;
- 幂等性:防重复扣减。
四、部署架构
- 容器化打包服务;
K8s编排、自动扩缩容;- 持久化存储、日志中心;
- 全程
CI/CD自动化发布。