//创建一个一维数组
int[] myIntegers; //声明一个数组引用
myIntegers = new int[100]; //创建含有100个int的数组 //创建一个二维数组
double[,] myDoubles = new double[10, 20]; //创建一个三维数组
string[,,] myStrings = new string[5, 3, 10]; //创建交错数组
Point[][] myPolygons = new Point[3][];
myPolygons[0] = new Point[10];
myPolygons[1] = new Point[20];
myPolygons[2] = new Point[30];
  • 0基一维数组的性能是最佳的.因为可以使用一些特殊的IL指令.

16.1 初始化数组元素

    // 1) 利用c#的隐式类型的局部变量功能:
var names1 = new string[] { "Alidan", "Grant" }; // 2) 利用C#的隐式类型的局部变量和隐式类型的数组功能:
var names2 = new[] { "Alidan", "Grant", null }; // 3) 额外的语法奖励(这里不能用var)
string[] names3 = { "Alidan", "Grant" }; // 4) 使用C#的隐式类型的局部变量\隐式类型的数组和匿名类型功能:
var kids = new[] { new { Name = "Aidan" }, new { Name = "Grant" } };
foreach (var kid in kids)
Console.WriteLine(kid.Name);

16.2 数组转型

  • 元素为引用类型的数组,如果维数相同,且元素源类型到目标类型存在隐式或显式转换,CLR 允许将数组元素从一种类型转型另一种.
  • CLR不允许将值类型元素的数组转型为其他任何类型,不过可用 Array.Copy 方法来模拟.
    //创建二维 FileStream 数组
FileStream[,] fs2dim = new FileStream[5, 10];
//隐式转型为二维 Object 数组
object[,] o2dim = fs2dim;
//显示转型为二维 Stream 数组
Stream[,] s2dim = (Stream[,])o2dim; //创建一维 Int32 数组(元素是值类型)
int[] ildim = new int[5];
//下面的代码创建元素为引用类型的数组,
//每个元素都是对已装箱 Int32 的引用
object[] obldim = new object[ildim.Length];
Array.Copy(ildim, obldim, ildim.Length);
  • 使用数组转型有性能损失,对数组元素赋值时,CLR必须在运行时检查数组包含元素的类型是否与新元素类型相符.
  • System.Buffer.BlockCopy() 方法比 Array.Copy() 方法快,但前者只支持基元类型,不提供像 Array 的 Copy 方法那样的转型能力.
  • Array.ConstrainedCopy 方法要么完成复制,要么抛出异常,总之不会破坏目标数组中的数据.

16.3 所有数组都隐式派生自 System.Array

16.4 所有数组都隐式实现 IEnumerable, ICollection 和 IList

  • System.Array 实现了 IEnumerable,ICollectionIList 三个接口,但未实现其对应的泛型接口.
  • CLR 创建一维 0 基数组类型时,CLR 自动使数组类型实现 IEnumerable<T>,ICollection<T>IList<T>(T是数组元素的类型) 接口.同时,还为数组类型的所有基类型实现这三个泛型接口,只要它们是引用类型(数组元素为值类型的,不为数组的基类型实现接口).

16.5 数组的传递和返回

  • 数组作为实参传给方法时,实际传递的是对该数组的引用.因此,被调用的方法能修改数组中的元素.
  • 方法返回数组对象时,如果元素数量为 0 ,**强烈建议返回一个空数组,而不是 null **,因为调用方法时可以省去 null 检查.

16.6 创建下限非零的数组

16.7 数组的内部工作原理

  • 访问一维 0 基数组的元素比访问非 0 基一维或多维数组的元素稍快.因为:

    1. 有一些特殊 IL 指令处理一维 0 基数组,导致 JIT 编译器生成优化代码;
    2. For 循环时,JIT 编译器会将对 Length 属性的调用结果缓存起来,每次迭代检查的都是这个临时变量.(不要自作聪明自己缓存 Length 结果)
  • 如要提升性能,可以用交错数组代替矩形数组.
  • 矩形数组的访问方式 a[x,y] ,交错数组的访问方式 a[x][y]

16.8 不安全的数组访问和固定大小的数组

    static class Program
{
static void Main(string[] args)
{
StackallocDemo();
InlineArrayDemo();
} private static void StackallocDemo()
{
unsafe
{
const int width = 20;
char* pc = stackalloc char[width]; //在栈上分配数组 string s = "Jeffrey Richter"; //15个字符 for (int index = 0; index < width; index++)
{
pc[width - index - 1] = (index < s.Length) ? s[index] : '.';
} //下面这行代码显示".....rethciR yerffeJ"
Console.WriteLine(new String(pc, 0, width));
}
} private static void InlineArrayDemo()
{
unsafe
{
CharArray ca; //在栈上分配数组
int widthInBytes = sizeof(CharArray);
int width = widthInBytes / 2; //Char类型占2个字节 string s = "Jeffrey Richter"; //15个字符 for (int index = 0; index < width; index++)
{
ca.Characters[width - index - 1] = (index < s.Length) ? s[index] : '.';
} //下面这行代码显示".....rethciR yerffeJ"
Console.WriteLine(new String(ca.Characters, 0, width));
}
}
} internal unsafe struct CharArray
{
//这个数组内联(嵌入)到结构中
public fixed char Characters[20];
}

在结构中嵌入数组,需满足:

  • 类型必须是结构(值类型);不能在类(引用类型)中嵌入数组.
  • 字段或其定义结构必须用 unsafe 关键字标记.
  • 数组字段必须用 fixed 关键字标记
  • 数组必须是一维 0 基数组.
  • 数组的元素类型必须是以下类型之一:Boolean,Char,SByte,Byte,Int16,Int32,UInt16,UInt32,Int64,UInt64,Single,Double

返回目录

<NET CLR via c# 第4版>笔记 第16章 数组的更多相关文章

  1. <NET CLR via c# 第4版>笔记 第19章 可空值类型

    System.Nullable<T> 是结构. 19.1 C# 对可空值类型的支持 C# 允许用问号表示法来声明可空值类型,如: Int32? x = 5; Int32? y = null ...

  2. <NET CLR via c# 第4版>笔记 第18章 定制特性

    18.1 使用定制特性 FCL 中的几个常用定制特性. DllImport 特性应用于方法,告诉 CLR 该方法的实现位于指定 DLL 的非托管代码中. Serializable 特性应用于类型,告诉 ...

  3. <NET CLR via c# 第4版>笔记 第17章 委托

    17.1 初识委托 .net 通过委托来提供回调函数机制. 委托确保回调方法是类型安全的. 委托允许顺序调用多个方法. 17.2 用委托回调静态方法 将方法绑定到委托时,C# 和 CLR 都允许引用类 ...

  4. <NET CLR via c# 第4版>笔记 第13章 接口

    13.1 类和接口继承 13.2 定义接口 C#用 interface 关键字定义接口.接口中可定义方法,事件,无参属性和有参属性(C#的索引器),但不能定义任何构造器方法,也不能定义任何实例字段. ...

  5. <NET CLR via c# 第4版>笔记 第12章 泛型

    泛型优势: 源代码保护 使用泛型算法的开发人员不需要访问算法的源代码.(使用c++模板的泛型技术,算法的源代码必须提供给使用算法的用户) 类型安全 向List<DateTime>实例添加一 ...

  6. <NET CLR via c# 第4版>笔记 第5章 基元类型、引用类型和值类型

    5.1 编程语言的基元类型 c#不管在什么操作系统上运行,int始终映射到System.Int32; long始终映射到System.Int64 可以通过checked/unchecked操作符/语句 ...

  7. <NET CLR via c# 第4版>笔记 第6章 类型和成员基础

    6.1 类型的各种成员 6.2 类型的可见性 public 全部可见 internal 程序集内可见(如忽略,默认为internal) 可通过设定友元程序集,允许其它程序集访问该程序集中的所有inte ...

  8. <NET CLR via c# 第4版>笔记 第7章 常量和字段

    7.1 常量 常量 是值从不变化的符号.定义常量符号时,它的值必须能够在编译时确定. 只能定义编译器识别的基元类型的常量,如果是非基元类型,需把值设为null. 常量的值直接嵌入代码,所以不能获取常量 ...

  9. <NET CLR via c# 第4版>笔记 第8章 方法

    8.1 实例构造器和类(引用类型) 构造引用类型的对象时,在调用类型的实例构造器之前,为对象分配的内存总是先被归零 .没有被构造器显式重写的所有字段都保证获得 0 或 null 值. 构造器不能被继承 ...

随机推荐

  1. BZOJ3297: [USACO2011 Open]forgot DP+字符串

    Description 发生了这么多,贝茜已经忘记了她cowtube密码.然而,她记得一些有用的信息.首先,她记得她的密码(记为变 量P)长度为L(1 <= L<=1,000)字符串,并可 ...

  2. Linux环境下的定时任务(转载)

    今天做了个数据库的备份脚本,顺便系统得学习一下Linux下定时执行脚本的设置.Linux下的定时执行主要是使用crontab文件中加入定制计划来执行,设置比Windows稍微复杂一些(因为没有图形界面 ...

  3. python pandas demo

    1. import pandas as pd web_stats = {,,,,,], ,,,,,], ,,,,,]} df = pd.DataFrame(web_stats) print(df.he ...

  4. lombok 中的@Data注解

    今天看到有代码中的Dao包中的类文件,写的极其简洁,甚至引起了开发工具InteliJ的报错,然后程序还能稳健地跑起来. import lombok.Data; @Data public class V ...

  5. jq 插件写法

    1.一次声明一个函数 $.fn.函数名 = function([options]){} $.fn.red=function(options){ var defaults = { 'color': 'r ...

  6. Codeforces 847B - Preparing for Merge Sort

    847B - Preparing for Merge Sort 思路:前面的排序的最后一个一定大于后面的排序的最后一个.所以判断要不要开始新的排序只要拿当前值和上一个排序最后一个比较就可以了. 代码: ...

  7. Vultr新推出3.5美元/月套餐,并且支持微信支付了

    先前Vultr重新推出了2.5美元/月的套餐,但是不支持IPv4,所以不那么受国内朋友的欢迎,迫于压力,这不最近就推出了3.5美元/月的套餐了,这个套餐是支持IPv4的,有需要的朋友可以上车了,htt ...

  8. js事件轮询机制

    console.log(1) setTimeout(function(){ console.log(2) },0); console.log(3) 毫无疑问:运行结果是1 3 2 也就是说:setTi ...

  9. JDBC 与 Bean Shell的使用(一)获取值,并且传递

    1.在使用Jmeter进行接口测试的时候,会使用到JDBC,连接数据库,操作数据库其得到的数据后续操作需要使用,这里我们使用了BeanShell的概念来获取JDBC的返回值 如下说明了联合使用的2种方 ...

  10. 『Scrapy』爬虫框架入门

    框架结构 引擎:处于中央位置协调工作的模块 spiders:生成需求url直接处理响应的单元 调度器:生成url队列(包括去重等) 下载器:直接和互联网打交道的单元 管道:持久化存储的单元 框架安装 ...