使用ReadOnlyMemory<T>替代IReadOnlyList<T>传递只读数组的弊端探讨
ReadOnlyMemory<T>传递只读数组的弊端 当你考虑用ReadOnlyMemory<T>替代IReadOnlyList<T>传递只读数组时,除了你已经注意到的LINQ操作不便外,还有以下几个明显的弊端:
LINQ与集合操作的额外开销与繁琐性
ReadOnlyMemory<T>并未实现IEnumerable<T>接口,因此无法直接使用任何LINQ扩展方法。每次需要进行过滤、映射等操作时,都必须通过MemoryMarshal.ToEnumerable()转换为可枚举对象,这不仅增加了代码的冗余度,还会产生额外的枚举开销。对比IReadOnlyList<T>直接调用LINQ方法的简洁性,ReadOnlyMemory<T>的集合操作体验差很多:// ReadOnlyMemory<T>的LINQ使用方式 MemoryMarshal.ToEnumerable(readOnlyMemory).Select(x => x * 2); // IReadOnlyList<T>的LINQ使用方式 readOnlyList.Select(x => x * 2);下标访问的间接性
IReadOnlyList<T>提供了直观的this[int index]索引器,可以直接通过下标访问元素;而ReadOnlyMemory<T>需要先获取其Span属性得到ReadOnlySpan<T>,再使用索引器访问,多了一层调用,降低了代码的可读性:// ReadOnlyMemory<T>的下标访问 var value = readOnlyMemory.Span[0]; // IReadOnlyList<T>的下标访问 var value = readOnlyList[0];与.NET集合生态的兼容性不足
.NET大部分框架库、第三方工具的API都是围绕IReadOnlyList<T>、IEnumerable<T>等标准集合接口设计的,比如序列化组件、UI绑定、集合工具类等。使用ReadOnlyMemory<T>传递数据时,往往需要额外转换为标准集合类型才能适配这些API,增加了适配成本。而ImmutableArray<T>本身实现了IReadOnlyList<T>,可以无缝对接这些场景。意图表达模糊
IReadOnlyList<T>的命名直接清晰地传达了“只读、可下标访问的集合”的设计意图,其他开发者能立刻理解参数的用途和约束;而ReadOnlyMemory<T>的核心定位是内存片段的抽象,用于处理非托管内存、池化内存或跨线程的内存块场景,用它传递普通只读数组会让其他开发者困惑你的真实意图,增加代码的维护成本。不必要的内存模型认知负担
ReadOnlyMemory<T>涉及内存所有者(MemoryManager<T>)、非托管内存管理等底层概念,对于仅仅需要传递只读数组的简单场景来说,引入了不必要的复杂度。团队中不熟悉.NET内存模型的开发者可能会产生误用,虽然针对数组的ReadOnlyMemory<T>是安全的,但这种额外的认知成本完全可以避免。
内容的提问来源于stack exchange,提问作者MarkusParker

