为什么System.Linq.Enumerable中没有SelectToArray方法

时间:2013-11-10 11:37:07

标签: c# .net arrays linq collections

所以我想问:为什么我们只有选择器返回一个可枚举的?例如,我经常出现这种情况,当我必须修改数组的每个值时,例如:

int[] a = {1,2,3,4,5};
a = a.Select(x=>x*2).ToArray();

所以这里我们得到一个可枚举的,只有在它之后我们才能将它转换回数组。 我们可以尝试使用Array.ForEach,但前提是我们可以修改源代码。但是如果我们有一系列的引用类型并且无法修改它们,我们应该写这样的东西

SomeClass[] a = FillSomeClassArray();
SomeClass[] b = a.Select(x=> ((SomeClass)x.Clone()).Modify()).ToArray();

就我而言,我使用自己的班级

public static class CollectionHelper
{
    public static TResult[] SelectToArray<T, TResult>(this ICollection<T> source, Func<T, TResult> selector)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (selector == null)
            throw new ArgumentNullException("selector");
        var result = new TResult[source.Count];
        int i = 0;
        foreach (T t in source)
        {
            result[i] = selector(t);
            i++;
        }
        return result;
    }
}

这里我们没有双重转换,当我们没有预测我们知道结果的长度时我们应该使用这些信息。我知道MS不应该做所有的工作而不是我,但是它的功能标准还不够。

1 个答案:

答案 0 :(得分:1)

向框架添加SelectToArray的最大问题是一致性。如果您添加SelectToArray,则还应添加以下各项:

  • CastToArray<T>
  • ConcatToArray<T>
  • RepeatToArray<T>
  • ReverseToArray<T>
  • SkipToArray<T>
  • OfTypeToArray<T>
  • TakeToArray<T>

虽然我们处于添加新方法的主题,但在列表中添加相同的优化有什么问题?现在我们还需要

  • SelectToList<T>(类似于启动它的那个)
  • CastToList<T>
  • ConcatToList<T>
  • ......依此类推 - 我相信你明白了。

考虑到了解目标数组或目标列表的大小所带来的微不足道的节省,这种重大的重构是不切实际的。你可以用这样一个简单的方法达到同样的效果:

static T[] CopyToArray(
    this IEnumerable<T> source
,   T[] result
,   int pos = 0
,   int? lengthOrNull = null
) {
    int length = lengthOrNull ?? result.Length;
    foreach (var item in source) {
        if (pos > length) break;
        result[pos++] = item;
    }
    return result;
}

现在调用者可以将现有的LINQ功能与此方法结合起来构成上述所有XyzToArray方法,如下所示:

IList<MyClass> data = ...
int[] res = data.Select(x => x.IntProperty).CopyToArray(new int[data.Count]);

您还可以将LINQ查询的结果写入现有数组的不同部分,如下所示:

IList<MyClass> data1 = ...
IList<MyClass> data2 = ...
int[] res = new int[data1.Count+data2.Count];
data1.Select(x => x.IntProperty).CopyToArray(res, 0, data1.Count);
data2.Select(x => x.IntProperty).CopyToArray(res, data1.Count, data2.Count);