从IEnumerable转换为IEnumerable <object>

Lin*_*gxi 13 c# linq arrays ienumerable language-lawyer

我更喜欢使用IEnumerable<object>,对于LINQ扩展方法是定义的,不是IEnumerable,所以我可以使用,例如,range.Skip(2).不过,我也喜欢使用IEnumerable,对于T[]隐式转换为IEnumerable是否T是引用类型或值类型.对于后一种情况,不涉及拳击,这是好的.结果,我能做到IEnumerable range = new[] { 1, 2, 3 }.似乎不可能将两者的优点结合起来.无论如何,IEnumerable当我需要应用LINQ方法时,我选择安顿下来并做一些演员.

这个 SO线程,我开始知道range.Cast<object>()能够完成这项工作.但它会产生性能开销,这在我看来是不必要的.我尝试执行直接编译时强制转换(IEnumerable<object>)range.根据我的测试,它适用于参考元素类型,但不适用于值类型.有任何想法吗?

仅供参考,问题源于 GitHub问题.我使用的测试代码如下:

static void Main(string[] args)
{
    // IEnumerable range = new[] { 1, 2, 3 }; // won't work
    IEnumerable range = new[] { "a", "b", "c" };
    var range2 = (IEnumerable<object>)range;
    foreach (var item in range2)
    {
        Console.WriteLine(item);
    }
}
Run Code Online (Sandbox Code Playgroud)

Che*_*hen 9

根据我的测试,它适用于参考元素类型,但不适用于值类型.

正确.这是因为IEnumerable<out T>是共变量,并且值类型不支持协方差/反方差.

我知道range.Cast()能够完成这项工作.但它会产生性能开销,这在我看来是不必要的.

IMO的性能成本(由拳击带来)是不可避免的,如果你想要一个带有一系列值类型的对象的集合.使用非通用IEnumerable将无法避免拳击,因为IEnumerable.GetEnumerator提供了IEnumerator它的.Current属性返回object.我宁愿总是用IEnumerable<T>而不是IEnumerable.所以只需使用该.Cast方法,忘记拳击.


lok*_*ing 2

反编译该扩展后,源代码显示:

public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
    {
      IEnumerable<TResult> enumerable = source as IEnumerable<TResult>;
      if (enumerable != null)
        return enumerable;
      if (source == null)
        throw Error.ArgumentNull("source");
      return Enumerable.CastIterator<TResult>(source);
    }

    private static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
    {
      foreach (TResult result in source)
        yield return result;
    }
Run Code Online (Sandbox Code Playgroud)

IEnumerable<object>这基本上除了放在第一位之外没有其他作用。

你说:

根据我的测试,它适用于引用元素类型,但不适用于值类型。

你是如何测试的?