(一)同一类型和不同类型的多个对象

如果需要使用同一类型的多个对象,就可以使用数组或集合(后面章讲)。

如果需要使用不同类型的多个对象,可以使用Tuple(元组)类型。

(二)简单数组

如果需要使用同一类型的多个对象,可以使用数组。数组是一种结构,它可以包含同一类型的多个元素。

1、数组的声明

在声明数组时,应先定义数组总元素的类型,其后是一堆空方括号和一个变量名。

例子:

以下代码声明了一个包含整形类型的数组

int[] intArray;

2、数组的初始化

声明了数组后,就必须为数组分配内存,以保存数组的所有元素。数组是引用类型,所以需要分配的是堆上的内存。为此,应使用new关键字,指定数组中元素的类型和数量来初始化数组的变量。

例子:

intArray = new int[10];

除了以上方式初始化,还有如下方式:

int[] intArray = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

int[] intArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

int[] intArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

3、访问数组元素

在声明和初始化数组后,就可以使用索引器访问其中的元素了。数组只支持有整型参数的索引器。

通过索引器传递元素编号,就可以访问数组。索引器总是以0开头,表示第一个元素。可以传递给索引器的最大值是元素个数减1,因为索引从0开始。

int[] intArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

int x = intArray[6];//7

int y = intArray[9];//0

还可以使用for循环访问:

for (int i = 0; i < intArray.Length; i++)

{

    Console.WriteLine(intArray[i]);

}

除了for循环还可以用foreach循环:

foreach (var item in intArray)

{

    Console.WriteLine(item);

}

4、使用引用类型

除了能声明预定义类型的数组,还可以声明自定义类型的数组。

Person[] personArray = new Person[3];

初始化后可以使用索引器为元素赋值:

personArray[0] = new Person();

personArray[1] = new Person();

personArray[2] = new Person();

(三)多维数组

一般数组(也称为一维数组)用一个整数来索引。多维数组用两个或多个整数来索引。

声明多维数组,需要在方括号中加上逗号。

例子:

声明二维数组

int[,] intTwoDim = new int[3, 3];

intTwoDim[0, 0] = 1;

intTwoDim[0, 1] = 2;

intTwoDim[0, 2] = 3;

intTwoDim[1, 0] = 4;

intTwoDim[1, 1] = 5;

intTwoDim[1, 2] = 6;

intTwoDim[2, 0] = 7;

intTwoDim[2, 1] = 8;

intTwoDim[2, 2] = 9;

例子:

声明三维数组

int[,,] intTwoDim = new int[2, 2, 2];

intTwoDim[0, 0, 1] = 1;

intTwoDim[0, 0, 2] = 2;

intTwoDim[0, 1, 1] = 3;

intTwoDim[0, 1, 2] = 4;

intTwoDim[0, 2, 1] = 5;

intTwoDim[0, 2, 2] = 6;

intTwoDim[1, 0, 1] = 7;

intTwoDim[1, 0, 2] = 8;

intTwoDim[1, 1, 1] = 9;

intTwoDim[1, 1, 2] = 10;

intTwoDim[1, 2, 1] = 11;

intTwoDim[1, 2, 2] = 12;

intTwoDim[2, 0, 1] = 13;

intTwoDim[2, 0, 2] = 14;

intTwoDim[2, 1, 1] = 15;

intTwoDim[2, 1, 2] = 16;

intTwoDim[2, 2, 1] = 17;

intTwoDim[2, 2, 2] = 18;

需要注意的是,声明数组后,就不能修改其阶数来了,并且数组使用初始化时,必须初始化数组的每个元素,不能遗任何元素。

(四)锯齿数组

多维数组的大小对应一个矩形,而锯齿数组的大小设置就比较灵活,在锯齿数组中,每一行都可以有不同的大小。

在声明锯齿数组时,要一次放置左右括号。在初始化锯齿数组时,只在第一对方括号中设置该数组包含的行数。定义各行中元素个数的第2个方括号设置为空,因为这类数组的每行包含的个数可能不同,需要用索引器进行赋值。

例子:

int[][] intJagged = new int[2][];

intJagged[0] = new int[1] { 1 };

intJagged[1] = new int[5] { 1, 2, 3, 4, 5 };

intJagged[2] = new int[2] { 1, 2 };

(五)Array类

用方括号声明数组其实是C#中使用Array类的表示法。

1、创建数组

Array类是一个抽象类,所以不能使用构造函数来创建数组。但除了可以使用C#语法创建数组实例外,还可以使用静态方法CreateInstance()创建数组。

例子:

Array intArray = Array.CreateInstance(typeof(int), 2);//创建数组

intArray.SetValue(1, 0);//使用setvalue赋值

intArray.SetValue(2, 1);

int[] intNewArray = (int[])intArray;//可以转化为int[]形式

2、复制数组

因为数组是引用类型,所以将一个数组变量赋予另一个数组变量,就会得到两个引用同一个数组的变量。复制数组可以使用Clone()方法或Copy()方法,它们的区别是Clone()方法会创建一个新的数组,而Copy()方法必须传递阶数相同且有足够元素的已有数组,但它们都是浅表复制。

如果需要包含引用类型的数组的深层副本,就必须迭代数组并创建新对象。

3、排序

Array类使用QuickSort算法对数组中的元素进行排序。Sort方法需要数组的元素实现IComparable接口,因为简单类型(string,int)实现了该接口所以可以排序。但自定义类型需要实现IComparable接口才能进行排序。

例子:

int[] intArray = { 21,3291,12,392,39,92,193};

Array.Sort(intArray);

foreach (var item in intArray)

{

    Console.WriteLine(item);

}

运行以上代码,结果如下:

(六)数组作为参数

数组可以作为参数传递给方法,也可以从方法中返回。

例子:

public static int[] ArraySort(int[] array)

{

    Array.Sort(array);

    return array;

}

1、数组协变

数组支持协变。这表示数组可以声明为基类,其派生类型的元素可以赋予数组元素。但数组协变只能用于引用类型,不能用于值类型。另外数组协变传入的参数如果不能满足方法内的条件,也只能在运行时通过抛出异常来解决。

2、ArraySegment<T>

结构ArraySegment<T>表示数组的一段,其包含关于数组段的偏移量和元素个数信息。

例子:

int[] intArray = { 0, 1, 2, 3, 4, 5 };

var intArraySegment = new ArraySegment<int>(intArray, 2, 2);

foreach (var item in intArraySegment)

{

    Console.WriteLine(item);

}

运行以上代码,结果如下:

需要注意的是,数组段不复制原数组的元素。

(七)枚举

1、IEnumerator接口

foreach语句使用IEnumerator接口的方法和属性,迭代集合中的所有元素。

泛型版本的IEnumerator<T>接口派生自IDisposable,因此定义了Dispose()方法,来清理枚举器占用的资源。

2、foreach语句

C#编译器会把foreach语句转化为IEnumerable接口的方法和属性。

例子:

foreach (var item in intArray)

{

    Console.WriteLine(item);

}

编译器会对foreach语句进行解析:

IEnumerator<int> enumerator = intArray.GetEnumerator();

while (enumerator.MoveNext())

{

    int i = enumerator.Current();

    Console.WriteLine(i);

}

3、yield语句

C#2.0添加了yield语句,以便于创建枚举器。yield return语句返回集合的一个元素,并移动到下一个元素上。yield break可停止迭代。

例子:

首先定义一个返回类型为IEnumertor<T>的GetEnumertor的方法

public class PersonCollection

{

    public IEnumerator<string> GetEnumerator()

    {

        yield return "张三";

        yield return "李四";

        yield return "王麻子";

        yield return "赵六";

    }

}

然后就可以使用foreach语句迭代集合了

PersonCollection personCollection = new PersonCollection();

foreach (var item in personCollection)

{

    Console.WriteLine(item);

}

运行以上代码,结果如下:

yield语句会生成一个枚举器,而不仅仅生成一个包含的项的列表。这个枚举器通过foreach语句调用。从foreach中依次访问每一项时,就会访问枚举器。这样就可以迭代大量的数据,而无需一次把所有的数据都读入内存中。

(八)元组

数组合并了相同类型的对象,元组合并了不同类型的对象。.NET Framework定义了8个泛型Tuple类和一个静态Tuple类,它们用作元组的工厂。元组用静态Tuple类的静态Create()方法创建。

var result = Tuple.Create<int, int>(1, 2);//创建2个参数的元组

var result1 = Tuple.Create<int, int, int, int, int, int, int, Tuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, Tuple.Create<int, int, int>(8, 9, 0));//创建10个(7个以上)参数的元组

var result_item = result.Item1;

var result1_item10 = result1.Rest.Item1.Item3;//访问2个参数元组的第一个参数

(九)结构比较

数组和元组都实现接口IStructuralEquatable和IStructuralComparable。这两个接口都是.NET 4新增的,不仅可以比较引用,还可以比较内容。这些接口都是显示实现的,所以在使用时需要把数组和元组强制转换为这个接口。IStructuralEquatable接口用于比较两个元组或数组是否有相同的内容,IStructuralComparable接口用于给元组或数组排序。

(十)小结

本章介绍了创建和使用简单数组、多维数组和锯齿数组的C#表示法。C#数组在后台使用Array类,这样就可以用数组变量调用这个类的属性和方法。

探讨了如何使用IComparable和IComparaer接口给数组中的元素排序,描述了如何使用和创建枚举器、IEnumerable和IEnumerator接口,以及yield语句。

最后介绍了如何在数组中组织相同类型的对象,在元组中组织不同类型的对象。

【读书笔记】C#高级编程 第六章 数组的更多相关文章

  1. 读书笔记 - js高级程序设计 - 第六章 面向对象的程序设计

      EcmaScript有两种属性 数据属性 和 访问器属性 数据属性有4个特性 Configurable Enumerable Writable Value   前三个值的默认值都为false   ...

  2. R in action读书笔记(3)-第六章:基本图形

    第六章  基本图形 6.1条形图 条形图通过垂直的或水平的条形展示了类别型变量的分布(频数).函数:barplot(height) 6.1.1简单的条形图 6.1.2推砌条形图和分组条形图 如果hei ...

  3. unix环境高级编程第六章笔记

    口令文件 阴影口令 组文件 附属组ID 登录账户记录 系统标识 口令文件<\h2> /etc/passwd文件是UNIX安全的关键文件之一.该文件用于用户登录时校验用户的口令,文件中每行的 ...

  4. R in action读书笔记(4)-第六章:基本图形(下)

    6.3直方图 hist() 其中的x是一个由数据值组成的数值向量.参数freq=FALSE表示根据概率密度而不是频数绘制图形.参数breaks用于控制组的数量.在定义直方图中的单元时,默认将生成等距切 ...

  5. UNIX系统高级编程——第六章-系统数据文件和信息-总结

    口令文件: /* The passwd structure. */ struct passwd { char *pw_name; /* Username. */ char *pw_passwd; /* ...

  6. 读书笔记 - js高级程序设计 - 第十一章 DOM扩展

      对DOM的两个主要的扩展 Selectors API HTML5  Element Traversal 元素遍历规范 querySelector var body = document.query ...

  7. 读书笔记 - js高级程序设计 - 第七章 函数表达式

      闭包 有权访问另一个函数作用域中的变量的函数 匿名函数 函数没有名字 少用闭包 由于闭包会携带包含它的函数的作用域,因此会比其它函数占用更多的内存.过度使用闭包可能会导致内存占用过多,我们建议读者 ...

  8. 读书笔记 - js高级程序设计 - 第五章 引用类型

      引用类型 和 类 不是一个概念 用typeof来检测属性是否存在 typeof args.name == "string"  需要实验 访问属性的方法 .号和[] 一般情况下要 ...

  9. 读书笔记 - js高级程序设计 - 第四章 变量 作用域 和 内存问题

      5种基本数据类型 可以直接对值操作 判断引用类型 var result = instanceof Array 执行环境 每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这 ...

随机推荐

  1. UiPath保存图片操作的介绍和使用

    一.保存图像 (Save Image)的介绍 可以将图像保存到磁盘的一种活动 二.保存图像 (Save Image)在UiPath中的使用 1. 打开设计器,在设计库中新建一个Sequence,为序列 ...

  2. svn提交报错Unexpected HTTP status 413 'Request Entity Too Large' on

    问题原因:nginx的client_max_body_size设置过小,默认 1M,如果请求的正文数据大于client_max_body_size,HTTP协议会报错 413 Request Enti ...

  3. Java服务假死后续之内存溢出

    一.现象分析 上篇博客说到,Java服务假死的原因是使用了Guava缓存,30分钟的有效期导致Full GC无法回收内存.经过优化后,已经不再使用Guava缓存,实时查询数据.从短期效果来看,确实解决 ...

  4. Metasploit(msf)利用ms17_010(永恒之蓝)出现Encoding::UndefinedConversionError问题

    Metasploit利用ms17_010(永恒之蓝) 利用流程 先确保目标靶机和kali处于同一网段,可以互相Ping通 目标靶机防火墙关闭,开启了445端口 输入search ms17_010 搜索 ...

  5. 抓到 Netty 一个隐藏很深的内存泄露 Bug | 详解 Recycler 对象池的精妙设计与实现

    欢迎关注公众号:bin的技术小屋,如果大家在看文章的时候发现图片加载不了,可以到公众号查看原文 本系列Netty源码解析文章基于 4.1.56.Final版本 最近在 Review Netty 代码的 ...

  6. 30m精度土壤类型、土壤质地、土壤有机质、土壤PH、土壤氮磷钾

    ​数据下载链接:数据下载链接 引言 全国土壤类型.质地.养分及变化等信息产品分为土壤类型数据.土壤质地数据.土壤养分数据及土壤变化数据等.该类产品是基于野外调查和实地采样,结合历史数据,建立全国土壤类 ...

  7. static 和 final(java)

    static: 1.1static修饰成员变量: 使用static修饰的成员变量不在对象的数据结构,而是类的基本信息(参数) 使用static修饰的成员可以直接使用,类名.成员的方式访问,而不需要再n ...

  8. 无用的IP黑名单

    无效的IP黑名单,有些还没有收集,在阿里云或者腾讯云的安全组里面设置,拦截不必要的IP,免得遭到攻击,也避免的CPU和内存过高 来源 备注82.102.21.217 拒绝 随机访问目录攻击,频繁69. ...

  9. Josephus问题(Ⅲ)

    题目描述 n个人排成一圈,按顺时针方向依次编号1,2,3-n.从编号为1的人开始顺时针"一二三...."报数,报到m的人退出圈子.这样不断循环下去,圈子里的人将不断减少.最终一定会 ...

  10. shell脚本函数及数组

    函数介绍: 函数function是由若干条shell命令组成的语句块,实现代码重用和模块话编程. 它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部 ...