摘要本文系统梳理了.NET开发人员在面试中常见的核心知识点涵盖从初级到中级的关键概念。内容分为初级.NET开发人员和中級.NET开发人员两大部分详细解析了进程与线程、Windows服务、内存管理、类型系统、反射、垃圾回收等20个重要主题旨在帮助开发者构建完整的.NET知识体系提升面试准备效率。初级.NET开发人员 - 任何使用.NET的人都应知道的核心概念1. 进程与线程概念、区别与联系进程Process是操作系统进行资源分配和调度的基本单位拥有独立的虚拟地址空间、代码、数据和系统资源。每个进程至少包含一个线程进程之间相互隔离不能直接共享内存空间。线程Thread是CPU调度的基本单位是进程内的执行单元。同一进程内的多个线程共享进程的代码段、数据段和系统资源但拥有独立的栈空间和程序计数器。核心区别资源分配进程是资源分配的基本单位线程是CPU调度的基本单位内存空间进程间内存相互隔离线程间共享进程内存空间通信方式进程间通信需要IPC机制线程间可直接通过共享内存通信创建开销创建进程开销大创建线程开销小稳定性一个进程崩溃不会影响其他进程一个线程崩溃可能导致整个进程崩溃多线程的优势在多核CPU环境下多线程可以充分利用CPU资源提高程序响应速度和吞吐量。但需要注意线程同步、死锁、竞态条件等问题。2. Windows服务特性、生命周期与管理Windows服务是在Windows操作系统后台运行的长时期运行程序通常没有用户界面以系统账户默认System或指定用户身份运行。与标准EXE程序的主要区别特性Windows服务标准EXE程序用户界面无标准UI通过服务控制管理器管理通常有图形界面或控制台界面生命周期随系统启动/停止或手动控制用户启动/关闭运行账户System账户或指定服务账户当前登录用户账户启动类型自动、手动、禁用、延迟启动用户手动执行交互性通常不与桌面交互直接与用户交互服务启动类型自动系统启动时自动启动服务手动需要用户或应用程序手动启动禁用服务被禁用无法启动延迟启动系统启动后延迟启动避免影响启动速度3. Windows进程内存限制与系统设计影响在32位Windows系统上单个进程可访问的最大内存地址空间为2GB用户模式另外2GB保留给内核模式使用。这是由32位系统的地址空间限制决定的2³² 4GB其中用户空间和内核空间各占2GB。计算公式单个进程最大内存 2^(处理器位数) / 232位系统2³² / 2 2GB64位系统理论上可达16EB实际受操作系统版本和物理内存限制与虚拟内存的关系单个进程能访问的最大内存量通常是系统最大虚拟内存的一半因为另一半需要分配给操作系统内核使用。对系统设计的影响大内存应用需要处理大量数据的应用程序如数据库、科学计算应考虑使用64位系统内存管理需要精细管理内存使用避免内存泄漏进程拆分对于需要大量内存的应用可考虑拆分为多个进程虚拟内存配置合理设置页面文件大小避免频繁的页面交换4. EXE与DLL执行文件与动态链接库EXE可执行文件包含程序入口点如Main方法可直接由操作系统加载执行拥有独立的进程空间通常包含完整的应用程序逻辑DLL动态链接库不包含程序入口点不能直接执行包含可被其他程序调用的函数、类、资源在运行时被加载到调用进程的地址空间支持代码重用和模块化开发.NET中的程序集在.NET中EXE和DLL都是程序集Assembly都包含IL代码、元数据和清单。区别在于EXE程序集包含入口点而DLL程序集不包含。5. 强类型与弱类型安全性与灵活性的权衡强类型语言定义在编译时确定变量类型类型检查在编译阶段完成特点类型安全、性能高、编译时错误检测示例C#、Java、C、TypeScript优势编译时类型检查减少运行时错误更好的IDE支持智能提示、重构性能优化编译器可进行类型相关的优化弱类型语言定义在运行时确定变量类型类型检查在运行阶段完成特点灵活、动态、开发快速示例JavaScript、Python、PHP、Ruby优势开发快速无需声明类型灵活的代码结构易于原型开发动态特性支持如eval、动态属性选择建议没有绝对的更好应根据项目需求选择。大型企业应用、系统软件适合强类型语言快速原型、脚本任务适合弱类型语言。C#作为强类型语言在.NET 4.0后引入了dynamic关键字提供了有限的动态类型支持。6. PID进程标识与故障排除PIDProcess Identifier是操作系统为每个进程分配的唯一数字标识符用于在系统内唯一标识一个进程。在故障排除中的应用进程监控使用任务管理器、Process Explorer等工具查看进程状态资源分析通过PID关联进程的CPU、内存、IO使用情况调试附加在Visual Studio中通过PID将调试器附加到目标进程性能分析使用性能计数器按PID跟踪进程性能指标进程终止通过taskkill命令或API终止问题进程常用命令# 查看所有进程及PID tasklist 按PID终止进程 taskkill /PID 1234 /F 查看特定进程的详细信息 wmic process where processid1234 get *7. TCP/IP端口监听限制在TCP/IP协议栈中单个端口在同一时刻只能被一个进程监听。这是由套接字Socket的绑定机制决定的独占绑定当进程绑定到某个端口后该端口就被该进程独占绑定冲突其他进程尝试绑定同一端口时会收到Address already in use错误例外情况SO_REUSEADDR选项允许同一端口被多个套接字绑定但通常用于特定场景如快速重启服务实际应用中的解决方案端口复用使用反向代理如Nginx、IIS ARR将请求分发到多个后端进程进程池主进程监听端口通过进程池处理连接如IIS的w3wp.exe不同协议TCP和UDP可以同时使用同一端口号8. GAC全局程序集缓存GACGlobal Assembly Cache是.NET Framework中的全局程序集缓存位于%windir%\assembly目录下。解决的问题程序集共享多个应用程序可以共享同一个程序集避免重复部署版本控制支持并行部署同一程序集的不同版本DLL Hell解决传统Windows中DLL版本冲突问题安全性强名称程序集提供身份验证和完整性保护GAC中的程序集要求必须具有强名称Strong Name包含公钥/私钥对签名包含版本号、文化信息和公钥标记程序集加载顺序检查GAC如果程序集有强名称应用程序基目录bin文件夹私有路径如probing指定的路径代码基位置如CodeBase指定的URL管理命令# 安装程序集到GAC gacutil /i MyAssembly.dll 从GAC卸载程序集 gacutil /u MyAssembly 查看GAC中的程序集 gacutil /l中级.NET开发人员 - 深入理解.NET平台1. 编程范式面向接口、面向对象与面向方面面向对象编程OOP核心概念封装、继承、多态设计原则SOLID原则单一职责、开闭原则、里氏替换、接口隔离、依赖倒置优势代码复用、模块化、易于维护局限横切关注点如日志、安全、事务难以模块化面向接口编程IOP核心思想针对接口编程而不是针对实现编程实现方式定义接口契约由具体类实现优势松耦合、易于测试、支持依赖注入应用插件架构、服务抽象、测试替身面向方面编程AOP核心概念将横切关注点cross-cutting concerns从业务逻辑中分离实现机制通过代理、拦截器、编译时织入等方式典型应用日志记录、性能监控、事务管理、安全检查.NET实现PostSharp、Castle DynamicProxy、ASP.NET Core中间件三者关系面向接口是面向对象的重要原则面向方面是对面向对象的补充专门处理横切关注点。2. 接口与抽象类契约与实现的平衡特性接口Interface抽象类Abstract Class定义行为契约只有方法签名部分实现的类可包含具体实现实现不能包含实现C# 8.0前可包含具体方法和抽象方法继承一个类可实现多个接口一个类只能继承一个抽象类构造函数不能有构造函数可以有构造函数字段不能包含字段C# 8.0前可以包含字段访问修饰符默认public不能使用其他修饰符可以使用各种访问修饰符版本兼容添加新成员会破坏现有实现添加具体方法不会破坏现有派生类选择原则需要多重继承时选择接口需要为派生类提供公共实现时选择抽象类定义行为契约时选择接口定义类型层次结构时选择抽象类3. 反射运行时类型探索与操作反射Reflection是.NET框架提供的在运行时检查、创建和操作类型、对象、程序集和模块的能力。反射的核心类System.Type表示类型声明System.Reflection.Assembly表示程序集System.Reflection.MethodInfo表示方法System.Reflection.PropertyInfo表示属性System.Reflection.FieldInfo表示字段反射的主要用途类型发现在运行时获取类型信息动态创建动态创建类型实例晚期绑定在运行时调用方法和访问属性特性处理读取和操作自定义特性代码生成动态生成IL代码示例代码using System; using System.Reflection; public class ReflectionExample { public static void Main() { // 获取类型信息 Type type typeof(string); Console.WriteLine($类型名称: {type.Name}); Console.WriteLine($完全限定名: {type.FullName}); Console.WriteLine($程序集: {type.Assembly.FullName}); // 获取所有公共方法 MethodInfo[] methods type.GetMethods(BindingFlags.Public | BindingFlags.Instance); Console.WriteLine($\n公共方法数量: {methods.Length}); // 动态创建实例 object instance Activator.CreateInstance(typeof(StringBuilder)); // 动态调用方法 MethodInfo appendMethod instance.GetType().GetMethod(Append, new Type[] { typeof(string) }); object result appendMethod.Invoke(instance, new object[] { Hello, Reflection! }); Console.WriteLine($动态调用结果: {result}); } }性能考虑反射操作比直接