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)
根据我的测试,它适用于参考元素类型,但不适用于值类型.
正确.这是因为IEnumerable<out T>
是共变量,并且值类型不支持协方差/反方差.
我知道range.Cast()能够完成这项工作.但它会产生性能开销,这在我看来是不必要的.
IMO的性能成本(由拳击带来)是不可避免的,如果你想要一个带有一系列值类型的对象的集合.使用非通用IEnumerable
将无法避免拳击,因为IEnumerable.GetEnumerator
提供了IEnumerator
它的.Current
属性返回object
.我宁愿总是用IEnumerable<T>
而不是IEnumerable
.所以只需使用该.Cast
方法,忘记拳击.
反编译该扩展后,源代码显示:
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>
这基本上除了放在第一位之外没有其他作用。
你说:
根据我的测试,它适用于引用元素类型,但不适用于值类型。
你是如何测试的?