以前我使用IEnumerable<T>
类型,如果我将集合作为方法的参数传递。
但是最近,我遇到了以类似方式创建的IEnumerable<T>
类型集合的问题:
var peoples = names.Select(name => new People(name));
在这种情况下,总是,如果我使用集合人(例如,foreach),它会创建类People的新实例,并且很容易导致错误。
所以我想问一下使用IEnumerable <T>
类型参数是否正确。我认为这可能会导致问题(参见上面的示例),不应使用此类型。您推荐哪些替代方案(ICollection<T>
,IList<T>
等)以及何时使用哪种替代方案?
或者您认为这是一个愚蠢的问题,因为Select方法中的对象创建只使用傻瓜?
当然,我知道我可以使用ToArray()
或ToList()
来解决问题。但是使用这种方法的其他人,却无法知道。我想知道如何通过选择正确的类型参数来防止这种情况。当我想要“枚举”对象时,列表或数组对我来说太具体了。
答案 0 :(得分:7)
IEnumerable
不是一个集合。这只是你可以“枚举”的东西。问题是没有将IEnumerable
传递给您的方法,问题是如果您使用LINQ(Select
方法),每次读取可枚举时它将再次执行代码。如果您只想执行一次,则可以使用ToArray()
或ToList()
方法:
var peoples = names.Select(name => new People(name)).ToList();
像这样你仍然可以将它传递给任何接受IEnumerable
(或List
)的方法,它只会为每个人创建一个实例。
修改强> 你的方法不应该担心这些问题。这是来电者的问题。使用可枚举而不是列表调用您的方法可能有充分的理由。调用者应该知道,如果将枚举传递给不同的方法,则可枚举给出不同的结果,所以你不必担心。
唯一的例外是如果在方法本身中多次枚举参数。在这种情况下,您应该将参数缓存在方法内的列表中,然后根据需要多次枚举列表。
答案 1 :(得分:2)
ToArray
和ToList
建议暴露的内容超出了人们最初的想法。我们很想将这个建议简单地说是在调用网站上调用ToList
/ ToArray
或在方法中首先调整问题,但问题是{{1}适当的 - 您可以从参数类型从IEnumerable<T>
更改为其他内容(如IEnumerable<T>
),这会将调用者的onus转换为实现此接口的内容(请注意{{1} }},ICollection<T>
,T[]
和List<T>
都可以)。这种方法的部分问题是这些接口代表可变集合,而IList<T>
通告该方法枚举项目 - 这只是我不喜欢这种方法的原因之一。
如果潜在的错误根本不是一个错误怎么办?也许调用者打算将这些作为防御性副本或哑数据对象 - 在后一种情况下,某些措施可能效率低下,但需要他们制作副本 - 但在这个提议的使用中它绝对不是一个错误。同样,一个大小适合所有推荐都不适合因为Collection<T>
对象不必终止 - 但要求传入的数组类型意味着无限(即计算)或仅仅大{ {1}}对象是不可能的。
无论如何,我认为你提出有关防御性编程的问题是正确的。但是,在这种情况下,我认为最好的解决方案是坚持使用IEnumerable<T>
,并根据他们在某些有限的情况下可能会引入错误的推测来教育而不是限制您的呼叫者。
解释引用:
设计以防止白痴问题的问题在于白痴是如此巧妙。
希望这会有所帮助。干杯!