是否有一种通用的方法将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>。

[编辑]作为一个扩展方法,它可以命名为:

public static class IEnumerableExt
{
    // usage: someObject.SingleItemAsEnumerable();
    public static IEnumerable<T> SingleItemAsEnumerable<T>(this T item)
    {
        yield return item; 
    }
}

我是不是遗漏了什么?

[Edit2]我们发现someObject.Yield()(正如@Peter在下面的评论中建议的那样)是这个扩展方法的最佳名称,主要是为了简洁,所以如果有人想获取它,这里是它和XML注释:

public static class IEnumerableExt
{
    /// <summary>
    /// Wraps this object instance into an IEnumerable&lt;T&gt;
    /// 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&lt;T&gt; consisting of a single item. </returns>
    public static IEnumerable<T> Yield<T>(this T item)
    {
        yield return item;
    }
}

当前回答

被归为“不一定是一个好的解决方案,但仍然……”一个解决方案”或“愚蠢的LINQ技巧”,你可以结合Enumerable.Empty<>()和Enumerable.Append<>()…

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Append("Hello, World!");

...或Enumerable.Prepend < >()……

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Prepend("Hello, World!");

后两种方法从。net Framework 4.7.1和。net Core 1.0开始就可用了。

如果真的打算使用现有方法而不是编写自己的方法,这是一个可行的解决方案,尽管我不确定这是否比Enumerable.Repeat<>()解决方案更清楚或更不清楚。这肯定是较长的代码(部分原因是Empty<>()不可能进行类型参数推断),并且创建了两倍的枚举器对象。

为了解决这个“你知道这些方法存在吗?”的问题,Array.Empty<>()可以替换为Enumerable.Empty<>(),但很难说这样做会使情况好转。

其他回答

被归为“不一定是一个好的解决方案,但仍然……”一个解决方案”或“愚蠢的LINQ技巧”,你可以结合Enumerable.Empty<>()和Enumerable.Append<>()…

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Append("Hello, World!");

...或Enumerable.Prepend < >()……

IEnumerable<string> singleElementEnumerable = Enumerable.Empty<string>().Prepend("Hello, World!");

后两种方法从。net Framework 4.7.1和。net Core 1.0开始就可用了。

如果真的打算使用现有方法而不是编写自己的方法,这是一个可行的解决方案,尽管我不确定这是否比Enumerable.Repeat<>()解决方案更清楚或更不清楚。这肯定是较长的代码(部分原因是Empty<>()不可能进行类型参数推断),并且创建了两倍的枚举器对象。

为了解决这个“你知道这些方法存在吗?”的问题,Array.Empty<>()可以替换为Enumerable.Empty<>(),但很难说这样做会使情况好转。

让我有点惊讶的是,没有人建议使用类型为T的参数重载方法来简化客户机API。

public void DoSomething<T>(IEnumerable<T> list)
{
    // Do Something
}

public void DoSomething<T>(T item)
{
    DoSomething(new T[] { item });
}

现在你的客户端代码可以这样做:

MyItem item = new MyItem();
Obj.DoSomething(item);

或者加上一个列表:

List<MyItem> itemList = new List<MyItem>();
Obj.DoSomething(itemList);

在c# 3.0中,你可以使用System.Linq.Enumerable类:

// using System.Linq

Enumerable.Repeat(item, 1);

这将创建一个只包含您的项目的新IEnumerable。

或者(如前所述)

MyMethodThatExpectsAnIEnumerable(new[] { myObject });

or

MyMethodThatExpectsAnIEnumerable(Enumerable.Repeat(myObject, 1));

顺便说一句,如果你想要一个匿名对象的空列表,最后一个版本也可以很好。

var x = MyMethodThatExpectsAnIEnumerable(Enumerable.Repeat(new { a = 0, b = "x" }, 0));

尽管对于一种方法来说,这有点过头了,但我相信有些人可能会发现交互式扩展很有用。

微软的交互式扩展(Ix)包括以下方法。

public static IEnumerable<TResult> Return<TResult>(TResult value)
{
    yield return value;
}

可以这样使用:

var result = EnumerableEx.Return(0);

Ix添加了在原始Linq扩展方法中没有的新功能,这是创建响应式扩展(Rx)的直接结果。

想想,Linq扩展方法+ Ix = Rx for IEnumerable。

你可以在CodePlex上找到Rx和Ix。