plugins/languages/csharp/skills/linq/SKILL.md
C# LINQ 查询与集合操作规范。覆盖 .NET 10 新操作符 (CountBy/AggregateBy/Index)、 方法链 vs 查询语法、延迟执行陷阱、EF Core 查询转换、Span<T> 高性能替代、 ToList/ToArray 时机、可枚举二次遍历、HashSet/DistinctBy。当编写数据查询、 集合处理、序列操作、优化 LINQ 性能, 或说 "LINQ"、"Where Select"、"GroupBy"、 "查询性能"、"IEnumerable"、"PLINQ"、"DistinctBy" 时加载。
npx skillsauth add lazygophers/ccplugin csharp-linqInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
LINQ 让代码声明式, 但用错会带来性能与正确性陷阱。
Where 可写在一行user、order, 避免单字母 xvar top = orders
.Where(o => o.Status == OrderStatus.Paid)
.GroupBy(o => o.CustomerId)
.Select(g => new { CustomerId = g.Key, Total = g.Sum(o => o.Amount) })
.OrderByDescending(x => x.Total)
.Take(10)
.ToList();
List<T> / T[]TryGetNonEnumeratedCount(out var n) 判数量不强求枚举// ❌ 每次遍历都重新查 DB
var q = db.Users.Where(u => u.Active);
foreach (var u in q) Log(u);
foreach (var u in q) Save(u);
// ✅
var users = await db.Users.Where(u => u.Active).ToListAsync(ct);
| 操作符 | 取代 |
|--------|------|
| CountBy(keySelector) | GroupBy(...).Select(g => new { g.Key, Count = g.Count() }) |
| AggregateBy(key, seed, agg) | 手写 GroupBy + Aggregate |
| Index() | Select((item, i) => (i, item)) |
| Chunk(n) | 手写批分 |
| DistinctBy(k) / UnionBy / ExceptBy / IntersectBy | 自定义 IEqualityComparer |
| MinBy / MaxBy | OrderBy(k).First() |
var hotTags = posts.CountBy(p => p.Tag).OrderByDescending(kv => kv.Value).Take(5);
Any() 优于 Count() > 0Count(predicate) 优于 Where(p).Count()FirstOrDefault(predicate) 合并谓词List 时 for 略快, 但优先可读ToList; 只在终点物化Contains 用 HashSet<T>, 避免 O(n²)Span<T> / ReadOnlySpan<T> 取代 LINQ on small arrays.AsParallel().WithDegreeOfParallelism(n)// 热路径: 单次扫描, 零分配
public int SumPositive(ReadOnlySpan<int> data)
{
var sum = 0;
foreach (var x in data) if (x > 0) sum += x;
return sum;
}
AsEnumerable 后)AsNoTracking() 读取无需跟踪的数据Include / ThenInclude / AsSplitQuerySelect(u => new UserDto(u.Id, u.Name))AsAsyncEnumerable() + 流式消费var page = await db.Orders.AsNoTracking()
.Where(o => o.CustomerId == cid)
.OrderByDescending(o => o.CreatedAt)
.Skip(skip).Take(pageSize)
.Select(o => new OrderListDto(o.Id, o.Amount, o.CreatedAt))
.ToListAsync(ct);
EF Core: ToListAsync/FirstOrDefaultAsync/AnyAsync/CountAsync, 全部接受 CancellationToken。
对 IAsyncEnumerable<T> 使用 System.Linq.Async 提供的异步 LINQ 操作。
| 反模式 | 修复 |
|--------|------|
| list.Count() > 0 | list.Any() 或 list.Count > 0 (ICollection) |
| list.OrderBy(k).First() | list.MinBy(k) |
| list.Where(p).Count() | list.Count(p) |
| list.Select(...).Where(...) | 调换: 先 Where 后 Select |
| Distinct() 自定义对象 | 实现 IEquatable<T> 或 DistinctBy(key) |
| 链中 ToList().Where(...) | 删除中段 ToList |
| 大集合 list.Contains(x) | HashSet<T> |
record / ImmutableArray<T>with 表达式产生记录副本development
Go 数据库规范——GORM Model 命名 ModelXxx、表名单数、枚举 uint8 + 常量、索引 idx_ 前缀 + deleted_at leading column、禁 time.Time 统一 int64 unix、禁指针/nullable 字段、TEXT/BLOB/JSON 禁 default、AutoMigrate 禁改主键。设计 DB model、写 GORM tag、建索引、做 migration 审查时触发。
development
Go HTTP API 规范——响应始终 200 + body code 字段、路由 /api/* 全 POST 单段 <Action><Model>、中间件逐路由注册禁 Group(prefix,mw...)、handler 仅返回 (rsp,error)、认证走 header。设计 HTTP API、写路由/handler/中间件时触发。
development
Go 项目结构规范——三层架构(API → Impl → State)、全局状态模式、internal/ 私有包、cmd/ 仅 main.go、go.work 多模块、禁止 Repository 接口和 DI 容器、struct 公共字段开头全 omitempty、handler var rsp 顶声明、禁 legacy migration。设计项目骨架、新建目录、组织包、做架构评审时触发。
development
Go 命名规范——Id/Uid 字段(非 ID)、IsActive/HasMFA 布尔前缀、CreatedAt 时间字段、接收者统一用 p、包名全小写无下划线、泛型类型参数描述性命名、集合字段 xxx_list 禁 xxxs 复数、Enum 0 值 XxxNil 禁 Unknown、禁 Status 统一 State、Set/Update 语义区分。定义结构体字段、函数、变量、包、接收者名、泛型、枚举时触发。