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>这基本上除了放在第一位之外没有其他作用。
你说:
根据我的测试,它适用于引用元素类型,但不适用于值类型。
你是如何测试的?
| 归档时间: |
|
| 查看次数: |
2203 次 |
| 最近记录: |