将单个项作为IEnumerable传递
将单个项作为IEnumerable传递
在C# 2.0的框架版本中,有一种常见的方式可以将类型为T
的单个项目传递给期望IEnumerable
参数的方法吗?\n目前我正在使用一个辅助方法(它是.Net 2.0的,所以我有一堆类似于LINQ的转换/投影辅助方法),但这似乎很愚蠢:\n
public static class IEnumerableExt { // 用法:IEnumerableExt.FromSingleItem(someObject); public static IEnumerableFromSingleItem (T item) { yield return item; } }
\n另一种方式当然是创建和填充一个List
或Array
,并将其传递给IEnumerable
。\n[编辑] 作为扩展方法,它可能被命名为:\n
public static class IEnumerableExt { // 用法:someObject.SingleItemAsEnumerable(); public static IEnumerableSingleItemAsEnumerable (this T item) { yield return item; } }
\n我是否遗漏了什么?\n[编辑2] 我们发现someObject.Yield()
(如下面的评论中@Peter建议的)是这个扩展方法的最佳名称,主要是为了简洁,所以这里还有XML注释,如果有人想要使用:\n
public static class IEnumerableExt { ////// 将此对象实例包装成由单个项目组成的IEnumerable<T>。 /// ///对象的类型。 /// 将被包装的实例。 ///由单个项目组成的IEnumerable<T>。 public static IEnumerableYield (this T item) { yield return item; } }
问题:为什么会出现(Passing a single item as IEnumerable
在讨论中,某些情况下了一个辅助方法作为解决方案,认为这是最干净的方法。如果传入一个列表或数组,那么不可信任的代码可能会将其强制转换并更改内容,在某些情况下导致奇怪的行为。虽然可以使用只读集合,但这可能需要更多的包装。有人认为这个解决方案非常简洁。
另外,某些情况下,如果传入的是一个数组,它怎么会被更改?可能可以将其强制转换为数组,然后将引用更改为其他内容,但这有什么好处呢?(不过我可能漏掉了什么...)
还某些情况下,假设你决定创建一个可枚举对象并传递给两个不同的方法...然后第一个方法将其强制转换为数组并更改内容。然后你将其作为参数传递给另一个方法,却不知道它的变化。我不是说这很可能发生,只是说当不需要可变性时,拥有可变性不如自然的不可变性简洁。
在问题讨论中,某些情况下了使用myDict.Keys.AsEnumerable()
方法时遇到了问题。经过重命名扩展方法SingleItemAsEnumerable
后,一切开始正常工作。问题是无法将IEnumerable<Dictionary<CheckBox,System.Tuple<int,int>>.KeyCollection>'转换为'IEnumerable<CheckBox>'。是否缺少一个强制转换?尽管可以暂时使用这个hack,但其他高级开发人员能找到更好的方法吗?
最后,某些情况下了MoreLINQ这个库,期望能在其中找到类似的解决方案,但没有找到。
问题的原因是传递单个项作为IEnumerable
在C# 3.0中,你可以使用System.Linq.Enumerable类来解决这个问题。使用Enumerable.Repeat(item, 1)可以创建一个只包含你的item的新的IEnumerable。
然而,有人认为这种解决方法会使代码变得更难阅读。因为对一个单独的元素使用Repeat方法可能会让人感到困惑。
有人认为使用Repeat一次是可行的,这样做更简单,而且不需要担心添加额外的扩展方法,并确保所使用的命名空间被包含。
也某些情况下可以使用new[]{ item }
来解决这个问题,他认为这是一个有趣的解决方法。
有人认为这个解决方法很好。
有人认为这个解决方法应该被接受。因为它易于阅读、简洁,并且在BCL中以单行代码实现,而不需要自定义扩展方法。
问题的出现原因:在调用一个方法时,如果方法的参数类型是IEnumerable,那么需要传递一个列表对象作为参数,即使列表中只有一个元素。
解决方法:可以将单个元素封装成一个列表对象,然后将该列表对象作为参数传递给方法。
代码示例:
IEnumerablemethod(IEnumerable items) { // 方法体 } T item = ...; // 单个元素 var list = new[] { item }; // 将单个元素封装成列表对象 method(list); // 传递列表对象作为参数
这样就可以将单个元素作为参数传递给期望接收IEnumerable类型参数的方法了。