是否有一种常见的方法将 T
类型的单个项传递给需要 IEnumerable<T>
参数的方法?语言是C#,框架版本2.0 .
目前我正在使用一个辅助方法(它是.Net 2.0,所以我有一大堆类似于LINQ的转换/投射辅助方法),但这看起来很愚蠢:
public static class IEnumerableExt
{
// usage: IEnumerableExt.FromSingleItem(someObject);
public static IEnumerable<T> FromSingleItem<T>(T item)
{
yield return item;
}
}
其他方式当然是创建和填充 List<T>
或 Array
并传递它而不是 IEnumerable<T>
.
[Edit] 作为扩展方法,它可能被命名为:
public static class IEnumerableExt
{
// usage: someObject.SingleItemAsEnumerable();
public static IEnumerable<T> SingleItemAsEnumerable<T>(this T item)
{
yield return item;
}
}
我在这里错过了什么吗?
[Edit2] 我们发现 someObject.Yield()
(正如@Peter在下面的评论中所建议的)是这个扩展方法的最佳名称,主要是为了简洁起见,所以如果有人想 grab 它的话,它会与XML注释一起:
public static class IEnumerableExt
{
/// <summary>
/// Wraps this object instance into an IEnumerable<T>
/// consisting of a single item.
/// </summary>
/// <typeparam name="T"> Type of the object. </typeparam>
/// <param name="item"> The instance that will be wrapped. </param>
/// <returns> An IEnumerable<T> consisting of a single item. </returns>
public static IEnumerable<T> Yield<T>(this T item)
{
yield return item;
}
}
15 回答
你的助手方法是最干净的方法,IMO . 如果你传入一个列表或一个数组,那么一段不道德的代码可能会抛出它并改变内容,在某些情况下会导致奇怪的行为 . 您可以使用只读集合,但这可能涉及更多包装 . 我认为你的解决方案尽可能整洁 .
我同意@EarthEngine 's comments to the original post, which is that ' AsSingleton'是一个更好的名字 . See this wikipedia entry . 然后从单例的定义得出如果一个空值作为参数传递,'AsSingleton'应该返回一个具有单个空值的IEnumerable而不是一个空的IEnumerable,这将解决
if (item == null) yield break;
争论 . 我认为最好的解决方案是有两种方法:'AsSingleton'和'AsSingletonOrEmpty';其中,如果将null作为参数传递,'AsSingleton'将返回单个空值,'AsSingletonOrEmpty'将返回空的IEnumerable . 像这样:然后,这些或多或少类似于IEnumerable上的'First'和'FirstOrDefault'扩展方法,这些方法感觉正确 .
虽然对于一种方法来说太过分了,但我相信有些人可能会发现Interactive Extensions非常有用 .
Microsoft的Interactive Extensions(Ix)包括以下方法 .
哪个可以这样使用:
Ix添加了原始Linq扩展方法中没有的新功能,并且是创建Reactive Extensions(Rx)的直接结果 .
想想
Linq Extension Methods
Ix
=Rx
forIEnumerable
.你可以找到Rx and Ix on CodePlex .
在C#3中(我知道你说过2),你可以编写一个通用的扩展方法,它可以使语法更容易被接受:
客户端代码然后
item.ToEnumerable()
.我有点惊讶的是,没有人建议使用类型为T的参数重新设置方法,以简化客户端API .
现在您的客户端代码可以执行此操作:
或列表:
IanG有a good post on the topic,建议
EnumerableFrom()
作为名称,并提到讨论指出Haskell和Rx称之为Return
. IIRC F#也称它为Return . F#的Seq calls the operator singleton<'T> .如果你准备成为C#中心的诱惑就是把它叫做
Yield
[暗指参与实现它的yield return
] .如果你对它的性能感兴趣,James Michael Hare也有returning zero or one items post,非常值得扫描 .
我参加派对有点晚了但是无论如何我会分享我的方式 . 我的问题是我想将ItemSource或WPF TreeView绑定到单个对象 . 层次结构如下所示:
项目>剧情>房间
总是只有一个项目,但我仍然希望在树中显示项目,而不必传递一个只有一个对象的集合,就像一些建议 .
因为你只能将IEnumerable对象作为ItemSource传递,所以我决定让我的类IEnumerable:
并相应地创建我自己的枚举器:
这可能不是“最干净”的解决方案,但它对我有用 .
EDIT
为了支持single responsibility principle,因为@Groo指出我创建了一个新的包装器类:
我用过这样的
EDIT 2
我用
MoveNext()
方法纠正了一个错误 .好吧,如果方法需要
IEnumerable
,你必须传递一个列表,即使它只包含一个元素 .通过
因为我觉得这个论点应该足够了
这可能不是更好,但它有点酷:
要么(如前所述)
要么
作为旁注,如果你想要一个匿名对象的空列表,例如,最后一个版本也可以很好 .
这个辅助方法适用于项目或许多项目 .
由于this C# compiler optimization,在
foreach
中使用时,这比yield
或Enumerable.Repeat
快30%,在其他情况下性能相同 .在这个测试中:
在C#3.0中,您可以使用System.Linq.Enumerable类:
这将创建一个仅包含您的项目的新IEnumerable .
我说的最简单的方法是
new T[]{item};
;没有语法可以做到这一点 . 最近的相当于我能想到的是params
关键字,但当然这需要你有权访问方法定义,并且只能用于数组 .正如我刚刚发现的,并且看到用户LukeH也提出过这样做的一个很简单的方法如下:
此模式允许您以多种方式调用相同的功能:单个项目;多个项目(以逗号分隔);数组;一个列表;枚举等
我不是百分之百确定使用AsEnumerable方法的效率,但它确实有效 .
更新:AsEnumerable函数看起来很有效! (reference)