在.Net 7中如何简化GetSubArray源码
前言
在Runtime源码更新中,有一个简化GetSubArray源码的更新,对GetSubArray还是有些印象的,在C#中切片功能就是调用GetSubArray函数实现的,如果不知道C#切片如何使用可以看这里: C#中的切片功能可以先看看上面这篇文章,因为里面有早期的GetSubArray源码,和下面的源码对比一下,发现现在的代码比原先的代码是简化过的,虽然改动并不大,但容易阅读,易于理解.
GetSubArray源码
public static T[] GetSubArray<T>(T[] array, Range range)
{
if (array == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
//range记录开始位置和结束位置,根据数组的长度,计算出子数组起始位置和长度
(int offset, int length) = range.GetOffsetAndLength(array.Length);
if (length == 0)
{
return Array.Empty<T>(); //如果为0,返回泛型长度为0的数组
}
T[] dest = new T[length]; //减少判断,根据长度分配泛型的数组
// Due to array variance, it's possible that the incoming array is
// actually of type U[], where U:T; or that an int[] <-> uint[] or
// similar cast has occurred. In any case, since it's always legal
// to reinterpret U as T in this scenario (but not necessarily the
// other way around), we can use Buffer.Memmove here.
//根据起始位置和长度,从数组从拷贝数据到子数组中
Buffer.Memmove(
ref MemoryMarshal.GetArrayDataReference(dest),
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), offset),
(uint)length);
return dest;
}
惯例还是用BenchmarkDotNet测试一下:
namespace net6perf
{
[DisassemblyDiagnoser(printSource: true, maxDepth: 3)]
public class GetSubArrayTest
{
public int[] array = new int[] { 1, 2, 3 };
[Params(1024, 2048)]
public int Count { get; set; }
[Benchmark]
public void Test()
{
int sum = 0;
for (int i = 0; i < Count; i++)
{
sum += array[^1];
}
}
}
}
通过基准测试,发现源码简化,没有带来性能提升,和.Net 6对比,性能相差不大.
秋风
2022-04-07