我有一个 IEnumerable<Object>
,需要将其作为参数传递给一个方法,但是这个方法需要 IReadOnlyCollection<Object>
。
是否可以将 IEnumerable<Object>
转换为 IReadOnlyCollection<Object>
?
一种方法是构建一个列表,并在其上调用AsReadOnly()
:
IReadOnlyCollection<Object> rdOnly = orig.ToList().AsReadOnly();
这将产生一个ReadOnlyCollection<object>
,它实现了IReadOnlyCollection<Object>
。
注意:由于List<T>
也实现了IReadOnlyCollection<T>
,因此调用AsReadOnly()
是可选的。虽然可以使用 ToList()
的结果调用方法, 但我更喜欢使用AsReadOnly()
,以便代码读者看到我调用的方法没有意图修改我的列表。当然,他们也可以通过查看我调用的方法的签名来发现同样的信息,但是直接表述会更明确。
由于其他答案似乎倾向于将集合包装在一个真正的只读类型中,让我补充一下。
我很少见到过调用方如此害怕一个接受 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>
,那么我会想知道有什么上下文需要我想要索引到列表并对其进行修改...答案通常是“没有”。)
orig.ToList().AsReadOnly()
,而是可以尝试以下操作:ReadOnlyCollection<object> rdOnly = Array.AsReadOnly(orig.ToArray());
这两种方法都需要相同次数的调用,但其中一种方法将另一种方法作为参数传入,而不是在返回值上调用。
.AsReadOnly()
有其用处。如果你只返回List<T>
,那么其他人可以执行rdOnly is IList<T>
并返回true
,但如果你执行.AsReadOnly()
,它将返回false
。如果我不知道我的使用者可能会尝试将我的结果转换为可变接口,则在返回结果之前,我经常会执行.AsReadOnly()
。 - Scott Chamberlain.ToArray()
方法而不是.ToList().AsReadOnly()
吗? - Mass Dot NetIReadOnlyCollection<T>
。 - Sergey KalinichenkoIReadOnlyCollection<T>
是IEnumerable<T>
的子集,因此您可以将其插入到任何需要IEnumerable<T>
的地方。 - Sergey Kalinichenko