所以我想问:为什么我们只有选择器返回一个可枚举的?例如,我经常出现这种情况,当我必须修改数组的每个值时,例如:
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不应该做所有的工作而不是我,但是它的功能标准还不够。
答案 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);