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

当前回答

有时候,当我觉得很顽皮的时候,我会这样做:

"_".Select(_ => 3.14)  // or whatever; any type is fine

这和少按shift键是一样的:

from _ in "_" select 3.14

对于一个实用函数,我发现这是最不冗长的,或者至少比数组更具自文档性,尽管它会让多个值滑动;作为加号,它可以被定义为一个局部函数:

static IEnumerable<T> Enumerate (params T[] v) => v;
// usage:
IEnumerable<double> example = Enumerate(1.234);

以下是我能想到的所有其他方法(这里是可运行的):

using System;
using System.Collections.Generic;
using System.Linq;

public class Program {
    
    public static IEnumerable<T> ToEnumerable1 <T> (T v) {
        yield return v;
    }
    
    public static T[] ToEnumerable2 <T> (params T[] vs) => vs;
    
    public static void Main () {
        static IEnumerable<T> ToEnumerable3 <T> (params T[] v) => v;
        p( new string[] { "three" } );
        p( new List<string> { "three" } );
        p( ToEnumerable1("three") ); // our utility function (yield return)
        p( ToEnumerable2("three") ); // our utility function (params)
        p( ToEnumerable3("three") ); // our local utility function (params)
        p( Enumerable.Empty<string>().Append("three") );
        p( Enumerable.Empty<string>().DefaultIfEmpty("three") );
        p( Enumerable.Empty<string>().Prepend("three") );
        p( Enumerable.Range(3, 1) ); // only for int
        p( Enumerable.Range(0, 1).Select(_ => "three") );
        p( Enumerable.Repeat("three", 1) );
        p( "_".Select(_ => "three") ); // doesn't have to be "_"; just any one character
        p( "_".Select(_ => 3.3333) );
        p( from _ in "_" select 3.0f );
        p( "a" ); // only for char
        // these weren't available for me to test (might not even be valid):
        //   new Microsoft.Extensions.Primitives.StringValues("three")
        
    }

    static void p <T> (IEnumerable<T> e) =>
        Console.WriteLine(string.Join(' ', e.Select((v, k) => $"[{k}]={v,-8}:{v.GetType()}").DefaultIfEmpty("<empty>")));

}

其他回答

有时候,当我觉得很顽皮的时候,我会这样做:

"_".Select(_ => 3.14)  // or whatever; any type is fine

这和少按shift键是一样的:

from _ in "_" select 3.14

对于一个实用函数,我发现这是最不冗长的,或者至少比数组更具自文档性,尽管它会让多个值滑动;作为加号,它可以被定义为一个局部函数:

static IEnumerable<T> Enumerate (params T[] v) => v;
// usage:
IEnumerable<double> example = Enumerate(1.234);

以下是我能想到的所有其他方法(这里是可运行的):

using System;
using System.Collections.Generic;
using System.Linq;

public class Program {
    
    public static IEnumerable<T> ToEnumerable1 <T> (T v) {
        yield return v;
    }
    
    public static T[] ToEnumerable2 <T> (params T[] vs) => vs;
    
    public static void Main () {
        static IEnumerable<T> ToEnumerable3 <T> (params T[] v) => v;
        p( new string[] { "three" } );
        p( new List<string> { "three" } );
        p( ToEnumerable1("three") ); // our utility function (yield return)
        p( ToEnumerable2("three") ); // our utility function (params)
        p( ToEnumerable3("three") ); // our local utility function (params)
        p( Enumerable.Empty<string>().Append("three") );
        p( Enumerable.Empty<string>().DefaultIfEmpty("three") );
        p( Enumerable.Empty<string>().Prepend("three") );
        p( Enumerable.Range(3, 1) ); // only for int
        p( Enumerable.Range(0, 1).Select(_ => "three") );
        p( Enumerable.Repeat("three", 1) );
        p( "_".Select(_ => "three") ); // doesn't have to be "_"; just any one character
        p( "_".Select(_ => 3.3333) );
        p( from _ in "_" select 3.0f );
        p( "a" ); // only for char
        // these weren't available for me to test (might not even be valid):
        //   new Microsoft.Extensions.Primitives.StringValues("three")
        
    }

    static void p <T> (IEnumerable<T> e) =>
        Console.WriteLine(string.Join(' ', e.Select((v, k) => $"[{k}]={v,-8}:{v.GetType()}").DefaultIfEmpty("<empty>")));

}

正如我刚刚发现的,也看到了用户LukeH的建议,一个很好的简单的方法如下:

public static void PerformAction(params YourType[] items)
{
    // Forward call to IEnumerable overload
    PerformAction(items.AsEnumerable());
}

public static void PerformAction(IEnumerable<YourType> items)
{
    foreach (YourType item in items)
    {
        // Do stuff
    }
}

此模式将允许您以多种方式调用相同的功能:单个项目;多个项目(逗号分隔);一个数组;一个列表;枚举等。

虽然我不能100%确定使用AsEnumerable方法的效率,但它确实有效。

更新:AsEnumerable函数看起来非常高效!(参考)

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

// using System.Linq

Enumerable.Repeat(item, 1);

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

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

微软的交互式扩展(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。

此helper方法适用于item或many。

public static IEnumerable<T> ToEnumerable<T>(params T[] items)
{
    return items;
}