前言

  如果需要使用相同的类型的多个对象,就可以使用集合和数组,这一节主要讲解数组,其中会重点涉及到Span<T>结构和ArrayPool数组池。我们也会先涉及到
简单的数组、多维数组、锯齿数组、Array类。

简单的数组、多维数组、锯齿数组

  简单的数组介绍

  数组的声明:
Int [] myArray;
  初始化:
myArray=new int[4];
  还可以:
Int [] myArray=new int []{1,2,3,4};
  访问数组:
myArray[0];
 

  多维数组介绍

  一般的数组(也称一维数组)是用一个数字来索引,多维数组用两个或两个以上的数字进行索引。

  声明多维数组时中间以,隔开,我们下面声明一个二维数组。
int [,] twodim=new int [3,3] int[,] twodim = { { 1,2,3}, { 4,5,6}, { 7,8,9} };
 

  一个三维数组。
int[,,] threedim = { { { 1,2},{ 3,4} }, {{ 5,6},{ 7,8} }, { { 9,10},{ 11,12} }
}; Console.WriteLine(threedim[0,1,1]);
 

  锯齿数组

  二维数组图形:


1

2

3


4

5

6


7

8

9

 

  

 

 

 

  锯齿数组



1

2


3

4

5

6


7

8

9

 

 

 

 

 


  在声明锯齿数组的时候要依次放置左右括号。在初始化锯齿数组时,只对第一对方括号中设置该数组包含的行数,定义各行中元素个数的第二个方括号设为空,因为这类数组的每一行包含不同的元素个数。
   int[][] jagged = new int[3][]; jagged[0] = new int[2] { 1, 2 }; jagged[1] =
new int[4] { 3, 4, 5, 6 }; jagged[2] = new int[3] { 7, 8, 9 };
 

Array类

  创建数组:
Array intArray1 = Array.CreateInstance(typeof(int), 5); for (int i = 0; i <
intArray1.Length; i++) { intArray1.SetValue(33, i);   }
  上面这段代码,描述了Array数组的创建以及设置值。CreateInstance()方法第一个参数为元素的类型,第二个参数为定义数组的大小。
SetValue()方法设置值第一个参数为设置IDE值,第二个参数为设置的索引。

  复制数组:
int[] intArray1 = { 1,2}; int[] intArray2 = (int[])intArray1.Clone();
  因为数组是引用类型的,所以将一个数组的变量赋予另一个数组变量,就会得到两个引用同一个数组的变量,这是使用的是Clone()方法创建数组的浅表副本。使用
Copy()方法也可以创建浅表副本,Clone()方法会创建一个数组,而Copy()方法必须传递阶数相同且有足够元素的已有数组。

  排序:
class Program { static void Main(string[] args) { int[] list = { 34, 72, 13, 44
,25, 30, 10 }; Console.Write("原始数组: "); foreach (int i in list) {
Console.Write(i+ " "); } Console.WriteLine(); // 逆转数组 Array.Reverse(list);
Console.Write("逆转数组: "); foreach (int i in list) { Console.Write(i + " "); }
Console.WriteLine();// 排序数组 Array.Sort(list); Console.Write("排序数组: "); foreach
(int i in list) { Console.Write(i + " "); } Console.WriteLine(); } }
 

  输出:
原始数组: 34 72 13 44 25 30 10 逆转数组: 10 30 25 44 13 72 34 排序数组: 10 13 25 30 34 44
72
  在上述方法中Array.Sort()方法实现了数组的排序,而Array.Reverse()实现了数组的逆转 。

ArrayPool数组池


  接下来重点来了,本文的重点一,ArrayPool数组池。如果一个应用需要创建和销毁许多的数组,垃圾收集器就要花费很多的功夫来做这些工作,为了较少垃圾收集器的工作,这里我们可以使用ArrayPool类来使用数组池。ArrayPool管理一个数组池,数组可以再这里租借内存,并且返回到这里。需要引用
using System.Buffers;

  创建数组池:

ArrayPool<int> arrayPool = ArrayPool<int>.Create(maxArrayLength:40000,
maxArraysPerBucket:10);
  maxArrayLength的默认值是1024*10224字节(数组的长度),maxArraysPerBucket默认值是50(数组的数量)。

  这里还可以使用以下方法来使用预定义的共享池。
ArrayPool<int> sharePool = ArrayPool<int>.Shared;
  下面我们就一起看看如何去使用这个数组池吧:

 
class Program { static void Main(string[] args) { //定义数组池 ArrayPool<int>
arrayPool = ArrayPool<int>.Create(maxArrayLength: 10000, maxArraysPerBucket: 10
);//定义使用数组的长度 int arrayLenght = 5; int[] array = arrayPool.Rent(arrayLenght); //
输出数组的长度 Console.WriteLine($"定义数组长度:{arrayLenght},实际数组长度:{array.Length}"); //
对数组进行赋值 array[0] = 0; array[1] = 1; array[2] = 2; array[3] = 3; array[4] = 4; //
输出数组的值 foreach (var item in array) { Console.WriteLine(item); } //
将内存返回给数组池,clearArray设置True清除数组,下次调用时为空,设置False,保留数组,下次调用还是现在的值
arrayPool.Return(array, clearArray:true); foreach (var item in array) {
Console.WriteLine(item); } } }
 

  在上面事例中,
我们使用Rent()方法请求池中的内存,Rent方法返回一个数组,其中至少包含所请求的元素个数。返回的数组可能会用到更多的内存,池中最少的请求为16个元素,紧接着是32,64,128以此类推。所以在上述例子中我们请求的长度为5,但是实际使用的元素个数为16个,多余的将根据类型对其赋值0或者null。


  我们使用Return()方法将数组返回到池中,这里使用了一个可选参数clearArray,指定是否清除该数组,不清除的话下一个从池中租用这个数组的人可以读取到其中的数据。清除数据可以避免这种情况,但是会消耗更多的CPU时间。

Span<T>

  Span<T>介绍


  为了快速访问托管或非托管的连续内存,可以使用Spam<T>结构。一个可以使用Span<T>结构的例子就是数组,Span<T>结构在后台保存在连续的内存中,另一个例子就是长字符串。

  使用Span<T>结构,可以直接访问数组元素。数组的元素没有复制,但是它们可以直接调用,并且比复制还快。
class Program { static void Main(string[] args) { int[] arr1 = { 3, 5, 7, 9, 11
,13, 15, 18, 19 }; var span1 = new Span<int>(arr1); span1[1] = 11;
Console.WriteLine(arr1[1]); } }
  输出:

 

 


  这里将创建的arr1数组传递给Span<T>,同时Span<T>类型提供了一个索引器,这里直接修改span1的第二个值,然后再输出arr1数组中的第二个值,也是被其修改过得值。

  Span<T>切片


  Span<T>它一个强大的特性是,可以使用它访问数组的部分或者切片,使用切片的时候不会复制数组元素,他们是从Span中直接访问的。下面代码介绍了创建切片的两种方法:
class Program { static void Main(string[] args) { //定义简单的数组 int[] arr2 = { 3, 5
,7, 9, 11, 13, 15, 18, 19, 20, 30, 40, 50, 60 }; //
Span<T>对数组进行切片,访问arr2数组,从第三个开始,取长度6个的一个数组。 var span3 = new Span<int>(arr2,
start:3, length: 6); //输出切片中的值 foreach (var item in span3) {
Console.WriteLine(item); } Console.WriteLine(""); Console.WriteLine("");
Console.WriteLine(""); //对span3进行切片处理,从第二个开始,去长度4个的一个数组 var span4 =
span3.Slice(start:2, length: 4); foreach (var item in span4) {
Console.WriteLine(item); } } }
 

  输出:

 

 

  使用Span<T>改变值

  前面介绍了如何使用Span<T>的索引器,更改数组的元素,下面介绍的将会有更多的选项,关于修改元素的值及复制。
class Program { static void Main(string[] args) { //定义简单的数组 int[] arr = { 3, 5,
7, 9, 11, 13, 15, 18, 19, 20, 30, 40, 50, 60 }; //将数组传递给span var span = new
Span<int>(arr); var span2 = new Span<int>(arr); //对span进行切片处理,从第四个开始 var span3
= span.Slice(start:4 ); //调用clear方法,用0填充span3 span3.Clear(); foreach (var item
in span3) { Console.WriteLine("span3的值:"+item); } Console.WriteLine("span3的长度:"+
span3.Length);//创建新的切片span4,从span2开始,长度3 Span<int> span4 = span2.Slice(start: 3
, length:3); //调用Fill方法,用传入的值填充span4 span4.Fill(42); foreach (var item in
span4) { Console.WriteLine("span4的值"+item); } Console.WriteLine("span4的长度"+
span4.Length);//将span4复制给span,复制失败 span4.CopyTo(span); //将span复制给span3 复制失败 if
(!span.TryCopyTo(span3)) { Console.WriteLine("复制不了"); } } }
 

  输出:

 

 

  上面事例中,
显示调用clear()方法,该方法用0填充Span,然后调用了Fill()方法,该方法用传递给Fill方法的值来填充Span,同时也可以将一个Span<T>复制给另一个Span<T>,这里先是采用的CopyTo,在这个方法中,如果另一个目标span不够大,就会复制失败,这里可以使用TryCopyTo来优化此功能,如果目标不够大,将会返回false。以此来判断是否复制成功。上面例子中span4长度为3,而span长度为14,这里是复制成功了,然后其下面的操作,因为span3的长度是10,span复制给span3失败了。因为span3不够大。


  上面事例中提供了改变值的一些方法,当我们不需要对值进行改变,只需要对数组进行读访问的时候,我们可以使用ReadOnlySpan<T>。这里定义了只读的Span
ReadOnlySpan<int> readonlySpan = new ReadOnlySpan<int>(arr);
 

总结


  在本篇文章中,重点介绍了ArrayPool数组池和Span<T>结构,通过使用数组池,来降低数组创建和销毁时消耗的性能,减少垃圾回收器的工作,使用Span<T>可以快速的访问托管及非托管代码,创建切片来对数组和长字符串进行一定的操作。更加高效的操作数组。

 

  青少年是一个美好而又是一去不可再得的时期,是将来一切光明和幸福的开端。——加里宁


  我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2n1gp5jweqww4

 

 

 

                      c#基础知识详解系列
<https://www.cnblogs.com/hulizhong/p/11205119.html>

 

  欢迎大家扫描下方二维码,和我一起学习更多的C#知识

 

 

 

  

 

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信