使用IEnumerable<;T>;在方法的参数中键入

本文关键字:参数 方法 gt IEnumerable lt 使用 | 更新日期: 2023-09-27 18:29:33

以前我使用IEnumerable<T>类型,如果我将collection作为方法的参数传递的话。

但最近,我对以类似方式创建的IEnumerable<T>类型的集合遇到了一个问题:

var peoples = names.Select(name => new People(name));

在这种情况下,如果我使用一个集合peoples(例如foreach),它总是会创建类People的新实例,并且很容易导致错误。

所以我想问一下使用IEnumerable <T>类型参数是否正确。我认为它可能会引起问题(见上面的例子),不应该使用这种类型。您推荐哪些替代方案(ICollection<T>IList<T>等)以及何时使用哪种替代方案?

或者你认为这是一个愚蠢的问题,因为在Select方法中创建对象只使用了一个傻瓜?

当然,我知道我可以使用ToArray()ToList(),从而解决问题。但是其他使用这种方法的人,它不可能知道。我想知道如何通过选择正确的类型参数来防止这种情况。当我只想"枚举"对象时,列表或数组对我来说太具体了。

使用IEnumerable<;T>;在方法的参数中键入

IEnumerable不是集合。这只是一些你可以"列举"的东西。问题不是将IEnumerable传递给您的方法,问题是如果您使用LINQ(Select方法),每次读取枚举值时,它都会再次执行代码。如果只想执行一次,可以使用ToArray()ToList()方法:

var peoples = names.Select(name => new People(name)).ToList();

像这样,您仍然可以将它传递给任何接受IEnumerable(或List)的方法,并且它只会为每个人创建一个实例。

编辑:你的方法不应该担心这些问题。这是来电者的问题。使用枚举值而不是列表来调用方法可能是有充分理由的。调用方应该知道,如果将enumerable传递给不同的方法,那么它会给出不同的结果,所以您不必担心这一点。

唯一的例外是在方法本身中多次枚举参数。在这种情况下,您应该将参数缓存在方法内部的列表中,然后根据需要多次枚举该列表。

ToArrayToList的建议比人们最初可能想到的要多。我们很容易认为这个建议只是简单地说,在调用站点或方法中的第一件事调用ToList/ToArray可以纠正问题,但您的问题是IEnumerable<T>是否合适——您可以将参数类型从IEnumerable<T>更改为其他类型(如ICollection<T>),这将使调用者有责任转换为实现该接口的类型(请注意,T[]List<T>IList<T>Collection<T>都可以)。这种方法的部分问题是,这些接口表示可变集合,而IEnumerable<T>宣传该方法枚举项,这也是我不喜欢这种方法的原因之一。

如果潜在的bug根本不是真正的bug怎么办?也许调用者打算将这些副本作为防御副本或哑数据对象——在后一种情况下,从某种程度上说,这可能效率低下,但要求他们制作副本也是如此——但在这种拟议的使用中,这绝对不是一个错误。同样,一刀切的建议也不适用,因为IEnumerable<T>对象不必终止,但要求传入数组类型意味着无限(即计算的)或仅仅是大的IEnumerable<T>对象是不可能的。

无论如何,我认为你提出有关防御性编程的问题是正确的。然而,在这种情况下,我认为最好的解决方案是坚持使用IEnumerable<T>,并对来电者进行教育,而不是基于他们可能在某些有限的情况下引入错误的猜测来限制他们。

引用的释义:

设计来防止白痴制造问题的问题在于,白痴是如此巧妙。

希望这能有所帮助。干杯