C# LINQ 从入门到精通——用 SQL 一样的语法操作集合,Where、Select、GroupBy 带你告别 foreach 地狱
目录为什么需要 LINQLINQ 的两种写法查询语法与方法语法最常用的 10 个标准查询运算符延迟执行 vs 立即执行重要概念LINQ to Objects 实战学生成绩分析LINQ to SQL 与 Entity Framework 初探综合实战员工薪资报表系统练习题答案及解析性能提示与避坑指南下一步学习建议1. 为什么需要 LINQ回想一下没有 LINQ 之前我们要从一个集合中筛选数据通常要写繁琐的foreach循环 if判断csharpListint numbers new Listint { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Listint evenNumbers new Listint(); foreach (var n in numbers) { if (n % 2 0) evenNumbers.Add(n); }这还只是最简单的筛选如果需要排序、分组、连接多个集合代码会变得又长又难维护。LINQLanguage Integrated Query语言集成查询就是为了解决这个问题而生的。它允许你用类似 SQL 的语法直接写在 C# 代码中对数组、集合、数据库、XML 等数据源进行统一的查询操作。核心优势可读性强查询意图一目了然类型安全编译时检查避免运行时错误统一 API无论数据源是什么查询语法都一样2. LINQ 的两种写法LINQ 提供了两种等价的写法你可以根据自己的喜好选择。2.1 查询语法Query Syntax看起来就像 SQL 语句使用from、where、select等关键字csharpint[] numbers { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // 查询语法筛选出偶数并按降序排列 var result from n in numbers where n % 2 0 orderby n descending select n; foreach (var item in result) Console.Write(item ); // 输出8 6 4 22.2 方法语法Method Syntax / Fluent Syntax使用扩展方法如Where、Select配合 Lambda 表达式csharpvar result numbers.Where(n n % 2 0) .OrderByDescending(n n); // 输出同上2.3 哪种写法更好查询语法更接近 SQL容易上手但功能有限不支持所有操作符如TakeWhile。方法语法更强大、更灵活几乎所有 LINQ 操作都能用。推荐混用复杂查询用查询语法特殊操作用方法语法。大多数 C# 开发者偏好方法语法。3. 最常用的 10 个标准查询运算符运算符作用示例方法语法Where条件筛选list.Where(x x 10)Select投影转换list.Select(x x * 2)SelectMany展平嵌套集合list.SelectMany(x x.Items)OrderBy/OrderByDescending升序/降序排序list.OrderBy(x x.Age)ThenBy/ThenByDescending次要排序list.OrderBy(x x.Age).ThenBy(x x.Name)GroupBy分组list.GroupBy(x x.Category)Join内连接list1.Join(list2, ...)GroupJoin分组连接左外连接list1.GroupJoin(list2, ...)Any/All是否存在/是否全部满足list.Any(x x 5)First/FirstOrDefault取第一个元素list.First(x x 5)Single/SingleOrDefault取唯一元素list.Single(x x 5)Skip/Take分页list.Skip(10).Take(20)Aggregate累计求和、拼接等list.Aggregate((a,b) a b)每个运算符都返回一个新的集合或单个值不会修改原始集合。4. 延迟执行 vs 立即执行重要概念这是新手最容易踩的坑4.1 延迟执行Deferred Execution像Where、Select、OrderBy这些返回IEnumerableT的操作符它们不会立即执行而是在你开始遍历结果时才真正去查询数据源。csharpvar numbers new Listint { 1, 2, 3 }; var query numbers.Where(n n 1); // 此时还没执行查询 numbers.Add(4); // 修改了数据源 foreach (var n in query) // 这里才执行查询会包含 4 { Console.WriteLine(n); // 输出 2, 3, 4 }好处每次遍历都获取最新数据且可以组合多个操作只遍历一次集合。4.2 立即执行Immediate Execution像ToList()、ToArray()、Count()、First()等操作会立即执行查询并返回结果集合或单个值。csharpvar numbers new Listint { 1, 2, 3 }; var listResult numbers.Where(n n 1).ToList(); // 立即执行 numbers.Add(4); foreach (var n in listResult) // 不会包含 4因为已经固化 { Console.WriteLine(n); // 输出 2, 3 }记住延迟执行的查询结果是一个“查询对象”每次遍历都会重新执行。立即执行的结果是快照不受后续数据源变化影响。5. LINQ to Objects 实战学生成绩分析我们用一个学生列表来演示各种 LINQ 操作。5.1 准备数据csharppublic class Student { public int Id { get; set; } public string Name { get; set; } public string Class { get; set; } // 班级 public int Score { get; set; } } ListStudent students new ListStudent { new Student { Id 1, Name 张三, Class A班, Score 85 }, new Student { Id 2, Name 李四, Class B班, Score 92 }, new Student { Id 3, Name 王五, Class A班, Score 78 }, new Student { Id 4, Name 赵六, Class B班, Score 88 }, new Student { Id 5, Name 孙七, Class A班, Score 95 }, new Student { Id 6, Name 周八, Class C班, Score 60 }, };5.2 常见查询示例csharp// 1. 成绩大于 80 的学生按分数降序 var highScorers students.Where(s s.Score 80) .OrderByDescending(s s.Score); foreach (var s in highScorers) Console.WriteLine(${s.Name} - {s.Score}); // 2. 只显示姓名和班级投影 var nameClass students.Select(s new { s.Name, s.Class }); foreach (var item in nameClass) Console.WriteLine(${item.Name} 在 {item.Class}); // 3. 按班级分组计算每个班的平均分 var groupByClass students.GroupBy(s s.Class) .Select(g new { Class g.Key, AvgScore g.Average(s s.Score), Count g.Count() }); foreach (var g in groupByClass) Console.WriteLine($班级 {g.Class}平均分 {g.AvgScore:F2}人数 {g.Count}); // 4. 最高分的学生使用 OrderByDescending First var topStudent students.OrderByDescending(s s.Score).First(); Console.WriteLine($最高分{topStudent.Name} - {topStudent.Score}); // 5. 是否存在不及格学生Any bool hasFailed students.Any(s s.Score 60); Console.WriteLine($存在不及格{hasFailed}); // 6. 所有学生是否都及格All bool allPassed students.All(s s.Score 60); Console.WriteLine($全部及格{allPassed}); // 7. 取前 3 名分页 var top3 students.OrderByDescending(s s.Score).Take(3); foreach (var s in top3) Console.WriteLine($前三名{s.Name} - {s.Score}); // 8. 跳过前 3 名取剩下的分页 var rest students.OrderByDescending(s s.Score).Skip(3); foreach (var s in rest) Console.WriteLine($其余{s.Name} - {s.Score});6. LINQ to SQL 与 Entity Framework 初探LINQ 不仅能查内存中的集合还能查数据库这是通过LINQ to SQL或Entity Framework Core实现的。当你使用 EF Core 时可以这样查询数据库csharpusing (var db new SchoolContext()) { // 查询成绩大于 80 的学生实际会生成 SQL 语句 var highScorers db.Students .Where(s s.Score 80) .OrderByDescending(s s.Score) .ToList(); }EF Core 会把你的 LINQ 表达式翻译成 SQL发送给数据库执行并返回对象。这就是LINQ to Entities。核心要点对于IQueryableTEF Core 查询LINQ 操作是延迟执行的直到ToList()等立即执行方法才会生成 SQL。你写的 LINQ 语句不会加载所有数据到内存而是生成高效的 SQL。7. 综合实战员工薪资报表系统我们将构建一个控制台程序使用 LINQ 对员工数据进行复杂的统计分析。7.1 数据模型csharppublic class Employee { public int Id { get; set; } public string Name { get; set; } public string Department { get; set; } public double Salary { get; set; } public DateTime HireDate { get; set; } }7.2 生成测试数据csharpListEmployee employees new ListEmployee { new Employee { Id 1, Name Alice, Department HR, Salary 5000, HireDate new DateTime(2020, 1, 15) }, new Employee { Id 2, Name Bob, Department IT, Salary 8000, HireDate new DateTime(2019, 5, 20) }, new Employee { Id 3, Name Charlie, Department IT, Salary 9500, HireDate new DateTime(2018, 3, 10) }, new Employee { Id 4, Name David, Department Sales, Salary 6000, HireDate new DateTime(2021, 7, 1) }, new Employee { Id 5, Name Eva, Department HR, Salary 5200, HireDate new DateTime(2020, 11, 12) }, new Employee { Id 6, Name Frank, Department IT, Salary 7000, HireDate new DateTime(2022, 2, 28) }, new Employee { Id 7, Name Grace, Department Sales, Salary 7500, HireDate new DateTime(2019, 9, 5) }, };7.3 完整报表功能csharpstatic void Main() { // 1. 各部门平均薪资降序 var deptAvg employees.GroupBy(e e.Department) .Select(g new { Dept g.Key, AvgSalary g.Average(e e.Salary) }) .OrderByDescending(x x.AvgSalary); Console.WriteLine( 各部门平均薪资 ); foreach (var item in deptAvg) Console.WriteLine(${item.Dept}: {item.AvgSalary:C}); // 2. 薪资最高的前 3 名员工 var top3 employees.OrderByDescending(e e.Salary) .Take(3) .Select(e new { e.Name, e.Salary, e.Department }); Console.WriteLine(\n 薪资 Top 3 ); foreach (var e in top3) Console.WriteLine(${e.Name} ({e.Department}) - {e.Salary:C}); // 3. 各部门入职人数按年份分组 var hireByDeptYear employees.GroupBy(e e.Department) .Select(g new { Dept g.Key, Data g.GroupBy(e e.HireDate.Year) .Select(y new { Year y.Key, Count y.Count() }) }); Console.WriteLine(\n 各部门年度入职人数 ); foreach (var dept in hireByDeptYear) { Console.WriteLine($【{dept.Dept}】); foreach (var yearData in dept.Data.OrderBy(y y.Year)) Console.WriteLine($ {yearData.Year}年: {yearData.Count}人); } // 4. 统计各部门薪资总额、最高、最低 var stats employees.GroupBy(e e.Department) .Select(g new { Dept g.Key, Total g.Sum(e e.Salary), Max g.Max(e e.Salary), Min g.Min(e e.Salary), Count g.Count() }); Console.WriteLine(\n 各部门薪资统计 ); foreach (var s in stats) Console.WriteLine(${s.Dept}: 总额 {s.Total:C}, 最高 {s.Max:C}, 最低 {s.Min:C}, 人数 {s.Count}); // 5. 找出公司内薪资高于部门平均薪资的员工关联子查询 var aboveDeptAvg employees.Select(e new { Employee e, DeptAvg employees.Where(emp emp.Department e.Department) .Average(emp emp.Salary) }) .Where(x x.Employee.Salary x.DeptAvg) .Select(x new { x.Employee.Name, x.Employee.Salary, DeptAvg x.DeptAvg }); Console.WriteLine(\n 高于部门平均薪资的员工 ); foreach (var item in aboveDeptAvg) Console.WriteLine(${item.Name} (薪资 {item.Salary:C}) 高于部门平均 {item.DeptAvg:C}); }7.4 运行效果部分输出text 各部门平均薪资 IT: $8,166.67 Sales: $6,750.00 HR: $5,100.00 薪资 Top 3 Charlie (IT) - $9,500.00 Bob (IT) - $8,000.00 Grace (Sales) - $7,500.00 ...8. 练习题练习 1基本筛选与投影给定一个整数列表Listint numbers new Listint { 5, 12, 8, 3, 20, 15, 7, 9 };用 LINQ 筛选出大于 10 的数字并按降序输出。将每个数字乘以 2然后输出。取出前 3 个偶数。练习 2分组与聚合订单系统定义一个Order类OrderId,CustomerId,Product,Quantity,Price。创建包含 6~8 个订单的列表。按CustomerId分组计算每个客户的订单总金额。按Product分组计算每种产品的总销量和总销售额。找出消费总额最高的客户 ID。练习 3复杂查询——员工与部门关联定义Department类DeptId,DeptName和Employee类EmpId,Name,DeptId,Salary。创建部门和员工的对应关系多个员工属于一个部门。使用Join查询每个员工的姓名、薪资和部门名称。按部门分组计算每个部门的平均薪资并输出部门名称和平均薪资。选做查询平均薪资高于公司平均薪资的部门。9. 练习题答案及解析练习1 答案csharp// 1. 大于10降序 var result1 numbers.Where(n n 10).OrderByDescending(n n); // 2. 每个乘2 var result2 numbers.Select(n n * 2); // 3. 前3个偶数 var result3 numbers.Where(n n % 2 0).Take(3);练习2 答案核心代码csharp// 按客户分组计算总金额 var customerTotal orders.GroupBy(o o.CustomerId) .Select(g new { CustomerId g.Key, Total g.Sum(o o.Quantity * o.Price) }); // 按产品分组 var productStats orders.GroupBy(o o.Product) .Select(g new { Product g.Key, TotalQuantity g.Sum(o o.Quantity), TotalSales g.Sum(o o.Quantity * o.Price) }); // 最高消费客户 var topCustomer customerTotal.OrderByDescending(x x.Total).First().CustomerId;练习3 答案Join 示例csharp// 1. Join 查询 var empWithDept employees.Join(departments, e e.DeptId, d d.DeptId, (e, d) new { e.Name, e.Salary, DeptName d.DeptName }); // 2. 按部门平均薪资 var deptAvg employees.GroupBy(e e.DeptId) .Join(departments, g g.Key, d d.DeptId, (g, d) new { DeptName d.DeptName, AvgSalary g.Average(e e.Salary) }); // 3. 高于公司平均的部门选做 double companyAvg employees.Average(e e.Salary); var aboveAvgDepts deptAvg.Where(x x.AvgSalary companyAvg);10. 性能提示与避坑指南⚠️ 陷阱1多次遍历同一个延迟查询csharpvar query numbers.Where(n n 5); int count query.Count(); // 第一次遍历 foreach (var n in query) { } // 第二次遍历如果数据源是数据库查询这会导致两次 SQL 执行。解决如果反复使用先ToList()缓存。⚠️ 陷阱2在 LINQ 中修改数据源在foreach遍历查询结果时修改原始集合会引发异常。应先ToList()再遍历。⚠️ 陷阱3滥用Count()判断是否为空csharpif (list.Count() 0) { } // ❌ 会遍历整个集合 if (list.Any()) { } // ✅ 只要发现一个元素就返回 true性能更好⚠️ 陷阱4在Where中调用耗时方法Where中的委托会在每次遍历时执行如果里面有耗时操作如网络请求性能会很差。解决先在内存中准备好数据或使用Select预处理。✅ 最佳实践优先使用Any()而非Count() 0。链式调用时把Where等筛选操作放在前面减少后续处理的数据量。对数据库查询避免在Where中使用不能翻译为 SQL 的本地方法如DateTime.Now的复杂计算。使用Select投影时只选择需要的字段减少数据传输量。11. 下一步学习建议表达式树Expression Trees了解 LINQ to SQL 背后的编译原理。PLINQ并行 LINQ利用多核处理器加速查询。动态 LINQ在运行时构建查询字符串可用于动态报表。深入 EF Core掌握导航属性、Include、过滤等高级查询。实战项目用 LINQ 重构之前的学生管理系统、游戏角色系统把循环全部替换成 LINQ 语句。最后的话LINQ 是 C# 开发者最爱的特性之一它让数据查询变得像呼吸一样自然。你可能一开始觉得查询语法和方法语法有点绕但只要坚持写几个实际场景就会爱上它。今天的员工报表系统演示了 LINQ 在真实业务中的威力——分组、聚合、排序、关联查询一气呵成代码清晰且易于维护。记住两条黄金法则延迟执行是双刃剑——善用它但也别忘了ToList()来固定结果。能 LINQ 的就别手写循环——除非有极端的性能要求否则 LINQ 的可读性和生产力远超手写。把上面的练习做一遍再试着用 LINQ 重写你以前写过的最复杂的查询逻辑你会感受到质的飞跃。下一篇我们将进入异常处理与调试的世界让你的程序在出错时也能优雅应对。我们下一篇见下一篇预告C# 异常处理与调试技巧——try-catch-finally全方位解读教你写健壮的程序并掌握 Visual Studio 调试利器。敬请期待全文完

相关新闻

Windows系统文件dnsext.dll丢失找不到问题解决

Windows系统文件dnsext.dll丢失找不到问题解决

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…

2026/10/12 22:21:48 阅读更多 →
AI 乱改代码?试试这套 SDD 规范驱动工作流

AI 乱改代码?试试这套 SDD 规范驱动工作流

在 AI Coding 快速普及的这两年,越来越多的团队开始使用 Codex、Cursor、Claude Code 等工具辅助开发。围绕这些工具,也出现了大量关于 Prompt、Skills、MCP 的使用教程。但很多内容都停留在“单点提效”层面:教你怎么写 Prompt、怎么装工具、…

2026/10/3 4:53:08 阅读更多 →
基于LangGraph搭建医疗智能分诊RAG Agent

基于LangGraph搭建医疗智能分诊RAG Agent

前言很多开发者做RAG智能体只会用LangChain线性Chain实现,一旦业务出现分支判断、循环重试、多工具并行、会话断点续跑、多用户长期记忆,代码会大量嵌套、逻辑割裂、难以维护,完全不适合线上生产。LangGraph 作为 LangChain 官方推出的状态图…

2026/10/15 11:29:32 阅读更多 →

最新新闻

光学工程师笔试题深度解析:从Zemax实操到公差分析的能力地图

光学工程师笔试题深度解析:从Zemax实操到公差分析的能力地图

简介:这是一份面向光学工程师求职者与光学相关专业学生的笔试真题文档,聚焦光学基础理论与工程应用能力的综合考查。内容涵盖图解法求像、填空题与计算题三大板块:图解法要求判断成像方向、标注理想光学系统基点位置与焦距;填空题…

2026/10/15 16:05:26 阅读更多 →
分数阶傅里叶变换的Matlab代码包:四种实现与图像加密

分数阶傅里叶变换的Matlab代码包:四种实现与图像加密

简介:分数阶傅里叶变换(FRFT)的MATLAB实现代码包,面向信号处理与图像分析方向的开发者及研究人员,解决传统FFT仅能进行0度和90度变换的限制,可在连续角度域对信号进行频谱分析。压缩包内共9个文件&#xff…

2026/10/15 16:05:26 阅读更多 →
ADS耦合器设计源文件改造与仿真验证全指南

ADS耦合器设计源文件改造与仿真验证全指南

简介:面向射频微波电路设计工程师、通信专业高年级学生以及电磁仿真入门者,这是一份基于ADS软件的耦合器设计源文件,适合用于学习定向耦合器在2.4GHz频段下的设计方法,也适合作为同类射频电路设计项目的参考模板。资源围绕中心频率…

2026/10/15 16:05:26 阅读更多 →
Fraunces 可变字体实战指南:桌面端与网页端的安装、选用与变体轴配置

Fraunces 可变字体实战指南:桌面端与网页端的安装、选用与变体轴配置

前端 【免费下载链接】beautiful-web-type In-depth guide to the best open-source typefaces: https://www.beautifulwebtype.com 项目地址: https://gitcode.com/gh_mirrors/be/beautiful-web-type 点击查看 免费下载 Fraunces 是一款由 Undercase Type 的 Phae…

2026/10/15 16:05:26 阅读更多 →
零基础如何写代码?从理解业务开始的学习路径

零基础如何写代码?从理解业务开始的学习路径

零基础如何写代码,是很多想进入软件开发领域的人遇到的第一个问题。常规建议是选一门编程语言,从变量、循环、函数学起,再逐步接触框架和数据库。这条路可行,但周期较长,对只想解决具体业务问题的人来说,投…

2026/10/15 16:05:26 阅读更多 →
AMQP接入物联网平台:连接断开、心跳与消费确认的实战复盘

AMQP接入物联网平台:连接断开、心跳与消费确认的实战复盘

凌晨两点手机震了,我以为是例行告警,结果是“AMQP连接断开”。那条消息来自我们刚上线不久的企业服务器接入物联网平台项目:设备数据本来应该通过 AMQP 通道源源不断回流到后端,结果网关一断,消息全堵在平台侧。我爬起…

2026/10/15 16:04:25 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →