[.net]数组

摘要:
使用以下命令:int[]nums=newint[10];多维阵列:也称为矩形阵列。使用以下命令:int[,]nums=newint[10,10];交错数组:图片每行的列数可以与行和列的列数不同。C#支持非零基数组,这意味着可以从零以外的数字对数组进行索引CreatInstance()方法来创建下限非零数组。int[]age=newint[]{10,20,30};//大括号中的数据项称为数组初始值设定项varage=newint[]{10,20,30}varage=new[]{10,20,30}//隐式类型推断C#的隐式类型推理为创建数组提供了良好的支持。

  在C语言中,数组是比较简单,也使用比较多的一种基础的数据结构。常用的有一维数组,二维数组等。但是在C#中,使用最多的是List,Dictionary等一些集合类,因为用他们来操作同类型的数据,比数组更加方便。当然,C#的数组Array也通过实现一些接口,提供了访问和操作数据的一些便捷方法。而在C语言中,都是比较不容易实现或者使用不方便。这也就是C#作为一门面向对象的语言的好处,虽然由此带来的性能损失,尤其在做算法相关的问题的时候。但退一步讲,在如今硬件资源比较丰富的情况下,日常场景中,这种性能损失还是可以接受的。


  接下来就聊聊C#种数组的那些事儿。

  1.数组基本概念:

      学习C#数组,首先需要明确一点,C#的数组是引用类型,即使数据基类型是值类型。作为引用类型,自然就会有类型对象指针,同步索引块,开销字段(overhead)等。

  2.C#数组分类:

      C#支持多维数组,也支持交错数组。并且他们都可以是非0基的。所谓非0基,是指数组第一个元素的索引不是从0开始。相应的,.Net CLR本身支持非0基数组,但是CLS规范规定所有数组都应该是0基数组,主要是为了兼容性和跨平台性,毕竟.Net家族除了C#还有VB,F#,C++(托管的)等语言。
      概念解释:
      一维0基数组:它又称为SZ数组(Single-dimension,Zero-based)或者向量。它的性能是最好的,因为编译器可以为他生成特殊的IL指令,实现JIT编译时候的优化,诸如以下指令(newarr,ldelem,ldelema,ldlen,stelem)。

          使用如下:

int[] nums=new int[10];


      多维数组:又称矩形数组。从行列的角度来考虑的话,它的每一行的列数都必须时相等的。

          使用如下:

int[,] nums=new int[10,10];

      交错数组:用行列的角度来考虑的画,它的每一行的列数可以不相同。

int[][] nums=new int[10][];
for(int i=0;i<10;i++)
{
      nums[i]=new int[10];//交错数组,各数组长度可不一样
}

         交错数组这个定义方式,非常类似于C语言中的动态多维数组,在C语言中,我们常用以下方法来开辟动态的二维数组

int i;
int** nums=(int**) malloc(sizeof(int*)*10);
for(i=0;i<10;i++)
{
    nums[i]=(int*)malloc(sizeof(int)*10);//这儿10是个实例,更具需求设置
}

         二者的定义的确有相似的地方,但应该注意到他们在本质上时不同的。

  3.数组索引:

      数组的索引是数组的一个很核心的概念,因为我们对数组的访问一般都是通过索引来实现的,但对索引的不当处理,可能导致程序终止。

      在C语言中,数组的索引控制都需要程序员来实现。如果发生索引超出数组范围,导致越界访问内存数据,甚至修改内存数据,这些都是不可察觉的,但无疑它为系统的奔溃留下了伏笔;

      在C#中,由于CLR要保证数据的安全,CLR在运行代码的时候,如果检测到数组索引超出范围,会立即抛出System.IndexOutOfRangeException异常,从而终止错误的继续。当然也可以使用unsafe关键字,来忽略CLR的这种默认行为。

      C#支持非0基数组,意味着数组可以的索引可以从非0的数开始,可以使用Arrary.CreatInstance()方法来创建下限非零数组。

  4.数组元素初始化:

     C#中为数组的初试化提供了一些甜蜜的语法糖。通常我们用以下几种方式来初始化一个数组。
      

int[] age=new int[]{10,20,30};//大括号中的数据项称为数组初始化器(arrar,initializer)
var age=new int[]{10,20,30}
var age=new [] {10,20,30};//隐式类型推断

     C#的隐式类型推断为创建一个数组提供了良好的支持。

  5.数组转型:

      类型转换是编程种很常见的一件事儿,我们把数组的类型转换又称为数组协变性(array convariance),在数组的转型的时候,需要满足以下几点条件:
      ①数组维数相同
      ②基类型存在隐式或显式类型转化
      需要注意以下几点:

        CLR不允许值类型数组转型为其他任何类型数组,但可以通过Array.Copy()变通实现。
        Array.Copy():支持装箱,拆箱,以及加宽基元类型(比如int到double的转变),但它是浅拷贝,即如果数组基类型是引用类型,则只复制其引用。
        System.Buffer.BliockCopy() 支持基元类型,但不具有转型能力
        System.Array.ConstrainnedCopy() 不支持装箱、拆箱和向下类型转化(父类到子类的转换),但它是可靠的,数据安全的,要么成功复制一个数组,要么不会修改目标数组的任何数据

  6.数组接口:

      数组实现了一些常用的接口,相当于给数组插上了访问的翅膀。
      System.Array数组基类实现了ICollection,IEnumerable,IList的非泛型版本,因为多维数组和非0基数组的原因,没有实现泛型版本(原因我也不太清楚)
      CLR单独为一维0基数组实现了泛型版本接口,包括其基类型,但是System.ValueType和Object除外

  7.数组做参数:

      在使用中,不可避免的要把数组作为一个参数来使用,那么在使用的时候,需要注意以下几点
      ①作为方法实参时传递的是引用;
      ②如果需要返回一个数组类型的字段,建议使用Array.Copy(),返回一个从该字段复制的数组,这么做是为了保证OOP的开放封闭原则,因为通常字段是私有的,不能被外部方法修改的和使用的;
      ③对于返回数组的方法,如果数组元素个数为0,仍不建议返回一个null,而是应该返回一个空的数组,这么做的目的在于对于方法返回参数的使用这来说,免去了null判断,防止产生空引用异常的错误。

  8.数组原理:

      实际在CLR内部只支持两种类型数组:一维0基数组 和 下限未知的一维或多维数组;
      一维0基数组:可以使用特殊的IL指令(newarr,ldelem,ldelema,ldlen,stelem),让编译器产生优化代码。比如索引检查发生的时刻提前,循环判断的提前的。
      下限未知的一维或多维数组:每次数组访问前验证索引有效性

  一些使用C#数组的建议:

  ①用交错数组代替矩形数组
  ②Unsafe关键字访问数组时可关闭索引上下限检查,支持常见的值类型和值类型结构(在fixed语句中)

  ③可以在线程栈上分配数组,利用stackalloc语句,类似于C语言alloca语句 ,条件是必须为一维0基数组,数组基类型为值类型

内容均来自于Jeffrey Richter的《CLR Via C#》第四版一书,以及个人总结和心得。学习深入了解C#,建议从这本书开始学习。

免责声明:文章转载自《[.net]数组》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇CentOS7安装桌面环境 并支持远程访问【python】flask+nginx配置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

解决c# md5与php md5加密不一致的问题(md5(unicode))

最近在做一个项目,客户是用c#编写的桌面应用程序,他在后台添加用户,需要我用php做一款app实现用户的一些基本功能。 首先是登陆,客户直接添加的用户密码采用了md5加密方式,我在app登陆的时候取出数据进行验证,验证密码的时候,一直提示密码不正确,于是我打印出php md5('123456') :md5: e10adc3949ba59abbe56e057...

Java高级开发_性能优化的细节

一、核心部分总结: 尽量在合适的场合使用单例【减负提高效率】 尽量避免随意使用静态变量【GC】 尽量重用对象,避免过多过常地创建Java对象【最大限度地重用对象】 尽量使用final修饰符【内联(inline)】 尽量使用局部变量【栈快】 尽量处理好包装类型和基本类型两者的使用场所【堆栈】 慎用synchronized,尽量减小synchronize的方...

ES6新增数组方法

1.扩展运算符可以将数组或者对象转为用逗号分隔的参数序列 let ary = [1, 2, 3]; ...ary // 1, 2, 3 console.log(...ary); // 1 2 3,相当于下面的代码 console.log(1,2,3); 2.扩展运算符可以应用于合并数组 let ary1 = [1, 2, 3]; let...

C++单元小结之Vector与迭代器(续),内置数组、vector和string,文件数据处理(文件操作续),字符串流(续)

C++单元小结 Vector(续) vector的用法: vector是长度可变的向量,可替代内置数组,更灵活,更高效。 要使用vector,必须包含头文件 定义vector时必须指定元素的类型,格式为: vector<元素类型> 变量名; 定义的同时可以初始化vector对象。下面是几种常见的初始化方法: //拷贝初始化 vector&...

VBScript学习笔记

(一)运算符 1. +运算符可连接字符串         fullname = firstname + " " + lastname     但推荐使用&运算符,&专用于字符串连接         fullname = firstname & " " & lastname 2. 算术运算符:         ^       ...

C# Byte[]数组读取和写入文件

protected void ByteToString_Click(object sender, EventArgs e) { string content = this.txtContent.Text.ToString(); if (string.IsNullO...