将IEnumerable转换为IReadOnlyCollection

62

我有一个 IEnumerable<Object> ,需要将其作为参数传递给一个方法,但是这个方法需要 IReadOnlyCollection<Object>

是否可以将 IEnumerable<Object> 转换为 IReadOnlyCollection<Object>

3个回答

85

一种方法是构建一个列表,并在其上调用AsReadOnly()

IReadOnlyCollection<Object> rdOnly = orig.ToList().AsReadOnly();

这将产生一个ReadOnlyCollection<object>,它实现了IReadOnlyCollection<Object>

注意:由于List<T>也实现了IReadOnlyCollection<T>,因此调用AsReadOnly()是可选的。虽然可以使用 ToList() 的结果调用方法, 但我更喜欢使用AsReadOnly(),以便代码读者看到我调用的方法没有意图修改我的列表。当然,他们也可以通过查看我调用的方法的签名来发现同样的信息,但是直接表述会更明确。


8
.AsReadOnly() 有其用处。如果你只返回 List<T>,那么其他人可以执行 rdOnly is IList<T> 并返回 true,但如果你执行 .AsReadOnly(),它将返回 false。如果我不知道我的使用者可能会尝试将我的结果转换为可变接口,则在返回结果之前,我经常会执行 .AsReadOnly() - Scott Chamberlain
@ScottChamberlain 这是一个非常重要的安全功能需要提及! - florien
7
你可以调用 .ToArray() 方法而不是 .ToList().AsReadOnly() 吗? - Mass Dot Net
1
@MassDotNet,你可以这样做,因为数组实现了IReadOnlyCollection<T> - Sergey Kalinichenko
@BenjaminSalerno IReadOnlyCollection<T>IEnumerable<T>的子集,因此您可以将其插入到任何需要IEnumerable<T>的地方。 - Sergey Kalinichenko
显示剩余3条评论

16

由于其他答案似乎倾向于将集合包装在一个真正的只读类型中,让我补充一下。

我很少见到过调用方如此害怕一个接受 IEnumerable<T> 的方法可能会恶意地尝试将该 IEnumerable<T> 强制转换回一个 List 或其他可变类型,并开始对其进行更改的情况。响起管风琴声和邪恶的笑声!

不。如果你正在使用的代码是合理的,那么如果它要求一个只有读功能的类型(IEnumerable<T>IReadOnlyCollection<T>等),它只会读取。

使用 ToList() 并解决问题。

顺便说一句,如果你正在创建相关的方法,通常最好仅请求 IEnumerable<T>,表示你“只想要一堆要读取的项”。你是否需要它的 Count 或需要多次枚举它是一个实现细节,肯定容易改变。如果需要多次枚举,只需这样做:

items = items as IReadOnlyCollection<T> ?? items.ToList(); // Avoid multiple enumeration

这样做可以将责任保持在本地(越接近越好),并使方法签名更加简洁。

另一方面,当返回一堆项目时,我更喜欢返回一个 IReadOnlyCollection<T>。为什么?目标是给调用者提供符合合理期望的东西 - 既不多也不少。这些期望通常是集合已实现且 Count 已知 - 这正是 IReadOnlyCollection<T> 提供了的内容(而一个简单的 IEnumerable<T> 并不具备)。通过不比这更具体,我们的契约与期望相匹配,该方法仍然可以自由更改底层集合。(相反,如果一个方法返回一个 List<T>,那么我会想知道有什么上下文需要我想要索引到列表并对其进行修改...答案通常是“没有”。)


3
作为dasblinkenlight答案的替代方案,为了防止调用者转换为List<T>,不要使用orig.ToList().AsReadOnly(),而是可以尝试以下操作:
ReadOnlyCollection<object> rdOnly = Array.AsReadOnly(orig.ToArray());

这两种方法都需要相同次数的调用,但其中一种方法将另一种方法作为参数传入,而不是在返回值上调用。


2
这甚至可能更快! - florien
@florien 为什么它可以更快?你能解释一下吗? - Soner from The Ottoman Empire
@snr 嗯,说实话,我无法用合理的解释来支持它。不知何故,我认为在这里,唯一的区别是类型首先被转换为数组还是列表,数组和与之配合的操作更加融入语言中,而由于集合不需要改变,因此列表在这里没有任何优势。虽然编译器确实可能对所有这些进行了优化。 - florien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接