我可以依靠 LINQ ToArray() 总是返回一个新实例吗?



我正在寻找一种简单的方法来克隆IEnumerable<T>参数以供以后参考。LINQ 的 ToArray 扩展方法似乎是执行此操作的好方法。

但是,我不清楚它是否总是保证返回一个新的数组实例。几个 LINQ 方法将检查可枚举对象的实际类型,如果可能,还会检查快捷方式;例如,Count()将查看该方法是否实现了ICollection<T>,如果是,将直接读取其Count属性;它仅在必要时迭代集合。

考虑到这种在实际情况下短路的心态,似乎,如果我在已经数组的东西上调用ToArray()ToArray()可能会短路并简单地返回相同的数组实例。这将在技术上满足ToArray方法的要求。

从快速测试来看,在 .NET 4.0 中,在数组上调用ToArray()确实会返回一个新实例。我的问题是,我可以依靠这个吗?我能保证ToArray总是返回一个新实例,即使在 Silverlight 和 .NET Framework 的未来版本中也是如此?在这一点上是否有明确的文档?

对于非空集合,ToArray将始终返回一个新数组 - 将其更改为返回现有值将是一个可怕的重大更改,我完全相信 .NET 团队不会这样做。就修改结果数组的效果而言,能够依赖它是一件重要的事情。可惜没有记录在案:(

LINQ to Objects 中有很多微妙的行为可能不值得依赖,但在这种情况下,它是如此巨大的行为,我会非常惊讶它的变化。

短路在不影响行为时很好,但通常 LINQ to Objects 非常适合仅在有效情况下进行优化。你可能想看看我的Edulinq系列中的两篇文章,介绍优化。

对于空源集合,某些版本将在每次调用时返回不同的空数组

,而某些版本将在每次调用时返回相同的数组。虽然这可能会破坏代码,但比改变实现"如果它已经是一个数组,只需返回它"的问题要小得多:空数组自然是不可变的,所以你能够观察到差异的唯一方法是你比较引用标识。

例:

var empty1 = new string[0];
var empty2 = new string[0];
var array1 = empty1.ToArray();
var array2 = empty2.ToArray();
// Prints True in some versions, and False in others
Console.WriteLine(ReferenceEquals(array1, array2));

由于ToArray方法是.NET框架内部的,因此我不会将自己的生命押在MS上,永远不会改变它。但是,我要做的是添加一个单元测试,断言 ToArray 返回一个新的数组实例。

Assert.AreNotSame(myArray, myArray.ToArray());

这样,如果以后更改 .NET 框架版本,将自动知道功能是否更改。

更新:Jon 已更新已接受的答案以涵盖此案例。

在撰写本文时,接受的答案是错误的。

如果IEnumerable<T>为空,则将取回单一实例Array.Empty<T>实例。

https://source.dot.net/#System.Linq/EnumerableHelpers.Linq.cs,75

通过 https://source.dot.net/#System.Linq/System/Linq/ToCollection.cs,10

相关内容

  • 没有找到相关文章

最新更新