在C#中创建只读数组的最佳方法是什么?

Vil*_*lx- 47 c# arrays readonly

我有一个非常不可能和原始的情况想要从我的财产返回一个只读数组.到目前为止,我只知道一种方法 - 通过System.Collections.ObjectModel.ReadOnlyCollection<T>.但这对我来说似乎有些尴尬,更不用说这个类失去了通过索引访问数组元素的能力(添加:哎呀,我错过了索引器).有没有更好的方法?什么可以使数组本身不可变?

Jef*_*tes 51

使用ReadOnlyCollection<T>.它是只读的,与你的信念相反,它有一个索引器.

数组不是不可变的,没有使用像这样的包装器就没有办法制作它们ReadOnlyCollection<T>.

请注意,创建ReadOnlyCollection<T>包装器是O(1)操作,不会产生任何性能成本.

更新
其他答案建议只将集合转换为较新的集合 IReadOnlyList<T>,扩展IReadOnlyCollection<T>为添加索引器.不幸的是,这实际上并没有让你控制集合的可变性,因为它可以被转换回原始集合类型并进行变异.

相反,您仍然应该使用ReadOnlyCollection<T>(List<T>方法AsReadOnly()Array静态方法AsReadOnly()帮助相应地包装列表和数组)来创建对集合的不可变访问,然后直接或作为它支持的任何一个接口公开它,包括IReadOnlyList<T>.

  • @gatopeich:无用是一个没有根据的陈述.请提供您的消息来源,说明它没有用处.但是很好的咆哮. (9认同)
  • `ReadOnlyCollection`不能用作不可变集合.它比一个数组有点__,但它周围有_more_代码.它的唯一'功能'不允许其_users_修改集合,但它甚至不保证对用户...底线:没用! (5认同)
  • 另请参阅@Warty 对 .NET 4.5 中`IReadOnlyList&lt;T&gt;` 的回答。 (2认同)

War*_*rty 11

引入的.NET Framework 4.5 IReadOnlyList<T>IReadOnlyCollection<T>添加扩展而来T this[int index] { /*..*/ get; }.

您可以从投T[]IReadOnlyList<T>.这样做的一个优点是可以(IReadOnlyList<T>)array理解的是等于array; 没有拳击.

当然,由于没有使用包装器,(T[])GetReadOnlyList()因此是可变的.

  • 我认为这归结为契约:如果我给你一个对象,那么我已经允许你使用该对象所暴露的任何方法.例如,如果您决定使用反射来窥视和操纵该对象的内部,那么所有保证都会丢失.同样,如果我给你一个IEnumerable <T>,那么我已经给你了枚举结果的权利.如果您决定直接将IEnumerable转换为List <T>并将其清除(读取:`(List <T>)result`而不是`result.ToList()`),那么您正在使用我没有的行为定义. (8认同)
  • 请注意,遍历 this 比遍历数组慢近十倍。 (2认同)

Mat*_*les 8

我认识到这是一个老问题,但现在有包含ImmutableArray类型的 .NET 包。内置于 .NET Core 3,并可通过NuGet获取完整框架 4.5 及以上版本


N8a*_*lan 7

从.NET Framework 2.0开始,有一个Array.AsReadOnly可以自动为您创建一个ReadOnlyCollection包装器.


BFr*_*ree 5

如果你真的想要一个返回的数组,但是担心数组的使用者会弄乱内部数据,只需返回一个数组的副本.就个人而言,我仍然认为ReadOnlyCollection<T>是要走的路,但如果你真的想要一个数组......

  • 看起来好像一个好主意,直​​到你意识到什么是class.MyArray [i]将在循环中完成.做1000次,你有1000个阵列的副本! (3认同)