C产品如何满足特定用户需求?
- 内容介绍
- 文章标签
- 相关推荐
本文共计777个文字,预计阅读时间需要4分钟。
直接使用+ImmutableList+。
ImmutableList.Create() 和 ImmutableList.Empty<T> 的区别在哪
两者都创建空实例,但语义和开销不同:
-
ImmutableList.Create<int>()返回一个含 0 个元素的树节点,有装箱/构造开销,适合后续链式调用(如.Add(1).Add(2)) -
ImmutableList<int>.Empty是静态只读单例,无分配、无装箱,适合纯占位或作为 Builder 起点 - 误用
new List<int>().AsReadOnly().ToImmutableList():多一层ReadOnlyCollection<T>包装,白跑一次遍历,还引入冗余引用
为什么 Add() 后不接返回值就等于没写
因为所有修改方法(Add()、Remove()、SetItem())都不改变原实例,只返回新实例:
-
list.Add(42);→ 原list仍是旧引用,新增元素丢失 -
var newList = list.Add(42);→ 正确,newList指向新树节点 - 链式调用如
list.Add(1).Remove(0).Insert(0, 99)可行,但每步都新建中间对象;100 次循环调用会生成 100 个临时树,内存和 GC 压力陡增
Builder 模式什么时候必须用
批量变更(>10 次增删改)或循环中累积操作时,不用 Builder 就是自找麻烦:
-
var builder = list.ToBuilder();开销极小,底层是可变数组,非树结构 -
builder.Add()、builder.RemoveAt()、builder[0] = x全部是 O(1) 操作 -
builder.ToImmutable()才真正构建平衡树,仅一次内存分配 - 已知容量?用
ImmutableList.CreateBuilder<T>(capacity)预分配,避免 builder 内部数组扩容拷贝
ImmutableList 和 ImmutableArray 哪个更适合只读高频访问
看场景选,不是越“不可变”越好:
- 需要频繁索引访问(如配置表查值)、且构建后永不修改 → 选
ImmutableArray<T>:底层是紧凑数组,array[i]是纯指针偏移,无虚调用、无装箱、无树跳转 - 需要后续仍可能小范围增删(如事件队列、状态快照链)→ 选
ImmutableList<T>:树结构支持高效插入/删除,但每次访问要多跳 1–2 层指针 - 误把
ImmutableList<T>当“高性能只读数组”用:访问延迟比ImmutableArray<T>高 3–5 倍,尤其在热路径上明显
真正容易被忽略的是:ImmutableList 的“不可变”不等于“零开销”。它的结构共享节省了复制内存,但换来的是间接访问成本。如果你的集合只读、固定、访问密集,优先走 ImmutableArray.CreateBuilder<T>().AddRange(...).ToImmutable() 这条路——这才是 .NET 里最接近“冻结数组”的做法。
本文共计777个文字,预计阅读时间需要4分钟。
直接使用+ImmutableList+。
ImmutableList.Create() 和 ImmutableList.Empty<T> 的区别在哪
两者都创建空实例,但语义和开销不同:
-
ImmutableList.Create<int>()返回一个含 0 个元素的树节点,有装箱/构造开销,适合后续链式调用(如.Add(1).Add(2)) -
ImmutableList<int>.Empty是静态只读单例,无分配、无装箱,适合纯占位或作为 Builder 起点 - 误用
new List<int>().AsReadOnly().ToImmutableList():多一层ReadOnlyCollection<T>包装,白跑一次遍历,还引入冗余引用
为什么 Add() 后不接返回值就等于没写
因为所有修改方法(Add()、Remove()、SetItem())都不改变原实例,只返回新实例:
-
list.Add(42);→ 原list仍是旧引用,新增元素丢失 -
var newList = list.Add(42);→ 正确,newList指向新树节点 - 链式调用如
list.Add(1).Remove(0).Insert(0, 99)可行,但每步都新建中间对象;100 次循环调用会生成 100 个临时树,内存和 GC 压力陡增
Builder 模式什么时候必须用
批量变更(>10 次增删改)或循环中累积操作时,不用 Builder 就是自找麻烦:
-
var builder = list.ToBuilder();开销极小,底层是可变数组,非树结构 -
builder.Add()、builder.RemoveAt()、builder[0] = x全部是 O(1) 操作 -
builder.ToImmutable()才真正构建平衡树,仅一次内存分配 - 已知容量?用
ImmutableList.CreateBuilder<T>(capacity)预分配,避免 builder 内部数组扩容拷贝
ImmutableList 和 ImmutableArray 哪个更适合只读高频访问
看场景选,不是越“不可变”越好:
- 需要频繁索引访问(如配置表查值)、且构建后永不修改 → 选
ImmutableArray<T>:底层是紧凑数组,array[i]是纯指针偏移,无虚调用、无装箱、无树跳转 - 需要后续仍可能小范围增删(如事件队列、状态快照链)→ 选
ImmutableList<T>:树结构支持高效插入/删除,但每次访问要多跳 1–2 层指针 - 误把
ImmutableList<T>当“高性能只读数组”用:访问延迟比ImmutableArray<T>高 3–5 倍,尤其在热路径上明显
真正容易被忽略的是:ImmutableList 的“不可变”不等于“零开销”。它的结构共享节省了复制内存,但换来的是间接访问成本。如果你的集合只读、固定、访问密集,优先走 ImmutableArray.CreateBuilder<T>().AddRange(...).ToImmutable() 这条路——这才是 .NET 里最接近“冻结数组”的做法。

