kitlau
kitlau

kitlau's blog

All Posts


Linq 和 lambda 的区别是什么?

这篇博客通过剖析LINQ与lambda表达式的本质差异揭示了现代开发者过度追求技术堆栈而忽视基础能力的普遍现象。文章指出LINQ作为语言集成查询的语法体系本质是基于IEnumerable的扩展方法库其核心价值在于将查询逻辑与数据源解耦而lambda表达式则是通过=>运算符简化委托创建的语法糖两者在技术层级上存在根本差异——前者是查询范式后者是函数式编程工具。当开发者习惯用lambda表达式构建Where等方法的谓词时实际上是在使用一种更简洁的委托创建方式这种混淆往往源于教学材料中二者的高频共现。文章通过代码示例展示了LINQ查询表达式如何编译为方法链调用并进一步解析lambda表达式如何通过表达式树实现动态查询构建的能力这种将代码转化为数据结构的特性正是LINQ能映射SQL等异构查询的底层原理。当开发者将lambda视为LINQ的必需组件时容易忽略其可选性——通过具名函数或委托同样能实现相同功能这恰说明lambda本质是语法便利而非技术依赖。博客最后抛出一个值得深思的问题:当我们在ORM框架中构建复杂查询时是否真正理解了表达式树与数据库查询语言之间的映射关系?这种对技术本质的追问或许正是每个开发者都需要回归的基础能力。--Qwen3

C# linq lambda expressions expression trees entity relationship mapping Method Syntax

一幅漫画解释 .NET 垃圾收集(GC)原理

这篇博客通过一幅漫画生动解析了.NET垃圾收集(GC)机制的核心原理并借此引发对技术深度学习的思考。文章以作者在年三十发布旧文的契机揭示了国内.NET开发领域普遍存在的技术浅层化现象——许多开发者长期停留在增删改查的流水线工作中导致对底层原理的认知缺失。作者通过翻译的漫画图解展示了GC分代回收机制与大对象堆(LOH)的内存管理逻辑并指出dotnet 5新增的POH分代特性可能带来的优化空间。特别值得关注的是文中提到的LOH压缩"解决方案"通过设置GCSettings.LargeObjectHeapCompactionMode参数实现手动干预的启发式策略既暴露了GC机制的复杂性也引发对"手动内存管理是否真的可取"的反思。作者在翻译漫画时保留了原作的直观表达同时通过个人职业观察提出了技术从业者如何突破业务驱动的困境:当我们将性能优化作为突破口时是否应该重新审视基础知识的系统性学习?在GC机制不断演进的当下如何平衡自动内存管理与手动优化的边界?这些问题或许能引导开发者从机械编码转向对技术本质的探索而漫画中那些看似简单的箭头与分区是否暗示着更深层的系统设计哲学?--Qwen3

.NET dotnet garbage collection performance optimization large object heap comic translation

C# required:跟 string 的空引用异常说再见

C# 11 的 required 关键字为开发者提供了一个优雅的解决方案来规避字符串类型的空引用异常问题。文章通过一个典型的数据库映射场景展示了传统开发模式中的痛点——当开发者将数据库字段设计为可为 null 但代码模型声明为 string 类型时,既可能触发编译器警告又可能在运行时引发 NullReferenceException。这种矛盾在 C# 11 之前需要开发者使用 null! 断言或者修改数据库约束来强行消除警告,但本质上只是将问题从开发阶段转移到生产环境。required 关键字的出现打破了这种妥协,它强制要求属性必须在初始化时赋值,从而在代码层面建立了不可变的约束。这种设计不仅消除了 null 值的可能性,更将数据完整性验证提前到了对象构造阶段。 文章更深层的讨论触及了软件开发领域的核心矛盾——在压缩工时与代码质量之间的博弈。当团队过度追求上线速度而忽视基础架构设计时,开发者被迫在代码中埋下隐患。required 关键字的出现恰恰揭示了一个值得深思的问题:当技术手段可以解决某个具体问题时,为何仍有大量项目选择在管理层面制造更多技术债务?文章通过对比外包模式与产品开发模式的异同,抛出了一个尖锐的质疑:在绩效考核体系驱动下,开发者是否正在沦为写代码的"码工"而非架构设计者?当单元测试被当作"不创造价值的累赘"时,我们究竟在用什么样的开发成本换取"快速上线"的光环?这些看似与技术无关的管理问题,或许才是导致空引用异常这类基础错误反复出现的根本原因。--Qwen3

C# Code Quality required keyword Nullables Engineering Practices Software Product Management

.NET 是如何编译的?如何阅读中间语言?

C#编译过程分为源代码转化为CIL再转化为Native code的三个阶段,其中CIL编译器负责静态编译生成包含局部变量初始化(.locals init)、栈深度声明(.maxstack)和操作码(如nop、ldarg、mul、add、stloc、ret)的中间代码,JIT编译器在运行时将CIL转换为处理器可执行的Native code。CIL通过操作码栈操作实现逻辑,如ldarg加载参数、mul/add进行算术运算、stloc存储局部变量,其中nop用于调试断点,br.s实现分支跳转。JIT编译虽带来性能开销但实现跨平台兼容,Native code难以直接阅读可通过ngen工具处理。学习IL有助于理解代码底层行为,对比操作性能差异,其中隐藏变量(如V_1)的出现与返回值拷贝机制相关,managed模式确保CLR元数据完整性,hidebysig控制方法重载隐藏逻辑。编译过程通过分层转换实现代码移植性与执行效率的平衡。--Qwen3

.NET performance optimization C# Compilation Intermediate Language JIT Compiler .NET Framework

【译】.NET SDK 将会内置容器支持,不再需要 Dockerfile

.NET 7 SDK引入了容器镜像构建功能,开发者可通过`dotnet publish`命令直接生成容器镜像,无需编写Dockerfile。该功能基于MSBuild属性实现自定义配置,支持镜像名称、版本、基础镜像等参数设置,适用于本地开发和CI管道场景。当前版本专注于Linux-x64架构,暂不支持Windows镜像和非x64架构,推送远程仓库需依赖Docker命令。核心局限包括不支持RUN命令执行系统操作、部分元数据自定义功能未实现,但计划在后续版本中完善。该功能通过简化容器构建流程(如GitHub Actions示例仅需30行配置),与传统Dockerfile相比减少了文件维护成本,未来将集成至SDK并逐步替代现有NuGet包。开发者可通过自定义基础镜像扩展功能,例如预装系统依赖,同时需关注预览阶段的已知限制,如身份验证支持待完善等问题。--Qwen3

.NET Docker .NET SDK Container Builds Linux x64 GitHub Actions

还在背依赖注入的概念?不如自己写一个依赖注入框架

文章通过构建一个简易的DI框架KDI演示了依赖注入的核心原理,重点对比了Singleton和Transient两种生命周期的行为差异。实现过程中通过Guid测试验证了Singleton在多次获取时返回相同实例,Transient则每次生成新实例。作者同时指出控制台应用中若未使用CreateScope方法,Scoped服务可能表现出与Singleton相似的特性,但通过显式创建Scope可验证Scoped实际会在不同作用域生成独立实例。最后批判了应试教育对编程学习的负面影响,强调通过实践理解技术本质的重要性,并指出Singleton服务在特定场景下可能表现出实例差异的复杂情况。--Qwen3

.NET DependencyInjection Dependency Injection Service Lifecycles Software Engineering Design Patterns

异步的原理是什么?C# 如何基于状态机实现异步?

C#异步通过状态机实现async/await机制,核心在于MoveNext方法的执行流程及状态切换。状态机通过state字段记录当前执行位置,结合switch-case跳转至对应代码块,实现异步操作的暂停与恢复。当await表达式执行时,若异步操作已完成(IsCompleted为true)则直接进入GetResult快速路径,否则保存当前状态至state字段并返回,等待后续恢复执行时通过状态码跳转至对应续延标签(如FirstAwaitContinuation)继续处理。状态机在暂停时通过builder.AwaitUnsafeOnCompleted注册回调,确保异步操作完成后触发MoveNext的再次调用。异常处理通过try-catch捕获异常并设置至builder,最终通过SetException传递结果,正常完成则调用SetResult。状态码-1表示尚未启动或正在执行,-2表示异常完成,0/1等数字对应不同await节点的状态,实现异步流程的精准控制。整个过程通过awaiter管理异步操作结果,结合状态保存与恢复机制,完成复杂的异步逻辑编排。--Qwen3

C# C# async programming State Machine Execution Paths Exception Handling Async Execution

什么是异步?异步就是多线程吗?异步就是 async、await 吗?

本文系统解析了C#异步编程的核心概念与实践方法重点阐述了Task异步任务模型的实现机制通过async/await关键字实现非阻塞操作的底层原理展示了Task.FromResult和Task.CompletedTask创建已完成任务的技巧分析了异步方法调用与await操作的执行时序揭示了不使用async修饰符也能返回Task的实现方式。通过多个代码示例验证了异步方法调用即刻执行的特性说明了await仅用于等待任务完成而非触发执行的逻辑,演示了Task.WhenAll实现多任务并行处理的优化方案,强调了理解异步编程原理对开发实践的重要性。--Qwen3

C# dotnet Async Await Task Parallelism Multithreading Task

EF Core 何时、为何使用 IsUnicode 方法

文章通过实验对比分析了EF Core中IsUnicode()配置在不同数据库中的实际作用。在MariaDB中该配置基本无效,因其UTF-8编码特性已默认支持Unicode;而在MSSQL Server中则会直接影响字段类型选择,使用IsUnicode(false)时生成varchar类型(非Unicode),默认或IsUnicode(true)生成nvarchar类型(Unicode)。作者建议仅在确定字符串为ASCII安全场景(如纯英文内容)时配置IsUnicode(false),以节省存储空间和提升性能,尤其在处理大规模数据时效果显著。同时警示需谨慎处理URL等字段,因用户可能输入非ASCII字符,且现代应用需兼容emoji等扩展字符集。文章还指出EF Core 6新增的[Unicode]属性特性,并强调开发者应避免过度优化导致功能缺陷,需权衡存储成本与数据兼容性。--Qwen3

C# EF Core Entity Framework Core IsUnicode Method Database Design Model Configuration

彻底理解 ASCII Unicode UTF-8 UTF-32 是什么以及区别与联系

本文系统梳理了计算机字符编码体系中的核心概念与逻辑关系。字素(grapheme)作为人类书写的最小单位,可由多个编码点(code point)构成,而每个编码点需通过特定编码方案(如ASCII、UTF-8、UTF-16)转换为字节序列。ASCII仅支持128个字符且字符代码与编码值一致,而Unicode字符集通过编码点(如👍对应U+1F44D)涵盖全球文字,其编码策略中UTF-8采用1-4字节变长编码,UTF-16固定16位编码。编码方式直接影响数据解析结果——误用ASCII解析UTF-8编码或反之均会导致乱码,且不同编程语言处理字符串长度时因编码策略差异产生矛盾(如C#的UTF-16编码中👍占2长度,Python Unicode字符串中占1长度)。开发者需区分"不可感知Unicode的函数"(按字节处理)与"可感知Unicode的函数"(按编码点处理),在精确场景中进一步采用"可感知字素的函数"。教育体系中需区分"字符集"(如ASCII/Unicode)与"编码方案"(如UTF-8/UTF-16)的层级关系,理解字符代码(code point)到字符编码(byte sequence)的转换过程,避免因编码认知不足引发的字符串处理异常。--Qwen3

dotnet ASCII Unicode UTF 8 Go Programming Language Character Encoding