C#高级编程笔记 Day 8, 2016年9月 28日 (数组)

1、数组的初始化

  声明了数组后,就必须为数组分配内存,以保存数组的所有元素。数组是引用类型,所以必须给它分配堆上的内存,为此,应使用 new 运算符,指定数组中元素的类型和数量来初始化数组的变量。若使用了为未分配的元素,就会抛出NullReferenceExceptonl 类型的异常。

  • int myArray=new int[4];

--> 在指定了数组的大小后,如果不复制数组中的所有元素,就不能重新设置数组的大小,如果事先不知道数组中应包含多少个元素,就可以使用集合。

下面使用数组初始化器为数组的每个元素赋值。数组初始化智能在声明数组变量时使用,不能在声明数组之后使用。

  • int[]  myArray=new int[4]{4,7,11,2};
    
    //或者
    
    int[] myArray=new int[]{4,7,11,2};.

2、数组支持协变,表示数组可以声明为基类,其派生类型的元素可以赋予数组元素。

  • 1 static Person[] GetPerson()
    2 {
    3     return new Person[]{
    4         new Person{FirstName="Damon",LastName="Hill"},
    5         new Person{FirstName="Niki",LastName="Lauda"},
    6         new Person{FirstName="Ayrton",LastName="Senna"}
    7     };
    8 }
  • 数组协变只能用于引用类型,不能用于值类型。数组协变有一个问题,它只能通过运行时异常来解决。如果把Person 数组赋予 object 数组,object数组就可以使用派生自object的任何元素。例如,编译器允许把字符串传递给数组元素。但因为object 数组引用Person 数组,所以就会出现以个运行时异常 ArrayTypeMismatchException.

3、ArraySegment<T>

  结构ArraySegment<T>表示数组的一段,如果需要使用不同的方法处理某个大型方法的不同部分,那么可以把相应的数组部分复制到各个方法中。此时,与创建多个数组相比,更有效的方法是使用一本数组。将整个数组传递给不同的方法。这些方法中只是用数组的某个部分。方法的参数除了数组以外,还应包括数组内的偏移量以及该方法应该使用的元素数。这样一来,方法就需要至少三个参数。当使用数组段时,只需要一个参数就可以了。ArraySegment<T>结构包含了关于数组段的信息(偏移量和元素个数)。

  SumOfSegments()方法提取一组ArraySegment<int>元素,计算改数组段定义的所有整数之和,并返回整数和

  •   

     1 static int SumOfSegments(ArraySegment<int>[] segments)
     2 {
     3     int sum=0;
     4     foreach(var segment in segments)
     5     {
     6         for(int i=segment.Offset;i<segment.Offset+segment.Count;i++)
     7         {
     8             sum+=segment.Array[i];
     9         }
    10     }
    11     return sum;
    12 } 

4、枚举:在foreach语句中使用枚举,可以迭代集合中的元素,且无须知道集合中的元素个数。foreach语句使用了一个枚举器。下图显示了调用 foreach 的客户端和集合之间的关系。数组或集合实现带GetEumerator()方法的IEumerable接口。GetEumerator()方法返回一个实现IEumerable接口的枚举。接着,foreach语句就可以使用IEumerable接口迭代集合了。

  • GetEnumerator()方法用IEnumerable接口定义。foreach语句并不真的需要在集合类中实现这个接口。有一个名为GetEnumerator()的方法,它返回实现了IEnumerator接口的对象就足够了

【扩展】

    .NET Framework 的核心时其运行库执行环境 即Common Language
Runtime,称为公共语言运行库(CLR)或.NET 运行库。通常将在CLR控制下
运行的代码称为托管代码(managed code)。
     但是,在CLR执行编写好的源代码(使用C#或其他语言编写的代码)之
前,需要编译它们。在.NET中,编译分为两个阶段:
    (1)将源代码编译为Microsoft 中间语言(IL)。
    (2)CLR把 IL编译为平台专用代码。
    这两个阶段的编译过程非常重要,因为Microsoft中间语言时提供.NET 的许多优点的关键。
    Microsoft中间语言与Java 字节码共享一种理念:他们都是低级语言,语法
很简单(使用数字代码,而不是文本代码),可以非常快速地转换为本地机器码。
对于代码,这种精心设计地通用语法有很重要地优点:平台无关性、提高性能、
和语言地互操作性。

5、IEnumerator接口

  foreach语句使用IEnumerator接口的方法和属性,迭代集合中的所有元素。为此,IEnumerator定义了Current属性,来返回光标所在的元素,该接口的MoveNext()方法移动到集合的下一个元素上,如果有这个元素,该方法就返回true。如果集合不再有更多的元素,该方法就返回false。

  foreach语句

  C#的foreach语句不会解析为IL代码中的foreach语句。C#编译器会把foreach语句转换为IEnumerable接口的方法和属性。下面是一条简单的foreach语句,它迭代persons数组中的所有元素,并逐个显示它们:

  • 1 foreach(var p in persons)
    2 {
    3     Console.WriteLine(p);
    4 }

    foreach 语句会解析为下面的代码段。首先,调用GetEnumerator()方法,获得数组的一个枚举器。在while循环中——只要MoveNext()返回true——就用Current属性来访问数组中的元素:

  • 1 IEnumerator<Person> enumerator=person.GetEnumerator();
    2 while(enumerator.MoveNext())
    3 {
    4     Person p=enumeratoe.Current;
    5     Console.WriteLine(p);
    6 }

6、yield语句:以便创建枚举器。

  yield ruturn 语句返回集合的一个元素,并移动到下一个元素。

  yield break 可停止迭代

  下面为一个使用yield return 语句实现一个简单集合的代码:HelloCollecetion 类包含GetEnumeration()方法。该方法实现代码包含两条 yield return 语句,它们分别返回字符串 Hello 和 World

  •  1 using System;
     2 using System.Collections;
     3
     4 namspace com.test.yinxi
     5 {
     6     public class HelloCollection
     7     {
     8         public IEnumerator<string>GetEnumerator()
     9         {
    10              yield return "Hello";
    11              yield return "World";
    12          }
    13     }
    14 }
  • 包含yield 语句的方法或属性也称为迭代块。迭代块必须声明为返回
    IEnumeration 或 IEnumerable 接口,或者这些接口的泛型版本,这个块
    可以包含多条 yield return 语句 或 yield break 语句,但不能包含 return 语
    句。

7、元组

  数组合并了相同类型的对象,而元组合并了不同类型的对象。.NET Framework 定义了8个泛型Tuple 类和一个静态Tuple类,它们用作元组的工厂,不同泛型Tuple 类支持不同数量的元素。方法Divid()返回包含两个成员的元组 Tuple<int,int>。泛型类的参数定义了成员的类型,它们都是整数。元组用静态 Tuple 类的静态 Create() 方法创建。Create() 方法的泛型参数定义了要实例化的元组类型,新建的元组用 result 和 raminder 变量初始化,返回这两个变量相除的结果。

  •  1 public static Tuple<int ,int> Divide(int dividend,int divisor)
     2 {
     3     int result =dividend/divisor;
     4     int reminder=dividend%divisor;
     5
     6     return Tuple.Create<int,int>(result,reminder);
     7 }
     8
     9 //调用
    10 var result=Divide(5,3);
    11 Console.WriteLine("result of division : {0},reminder: {1}",result.Item1,result.Item2);

  如果元组包含的项超过8个,就可以使用带8个参数的Tuple类定义。最后一个模板参数是TRest,表示必须给它传递一个元组。这样,就可以创建带任意参数的元组了。

  • public class Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>

    其中,最后一个模板参数是一个元组类型,所以可以创建带任意多项的元组:

  • var tuple =Tuple.Create<string,string,string ,int ,int ,int ,double, Tuple<int,int>>("Stenphanie","Alina","Nagel",2009,6,2,1.37,Tuple.Create<int,int>(52,3490));

8、【专题】结构比较

  数组和元组都实现接口IStructuralEquatable和IStructuralComparable。这两个接口都是.NET 4 新增的,不仅可以比较引用,还可以比较内容。这些接口都是现实实现的,所以在使用时需要把数组和元组强制转换为这个接口。IStructuralEquatable接口用于比较两个元组或数组是否有相同的内容,IStructuralComparable接口用于给数组或元组排序。下面为一个实现 IEquatable 接口的Person类。IEquatable接口定义了一个强类型化的Equals()方法,以比较FirstName 和LastName属性的值。

  •  1 public class Person :IEquatable<Person>
     2 {
     3     public int Id{get;private set;}
     4     public string FirstName{get;set;}
     5     public string LastName{get;set;}
     6
     7     public override string ToString()
     8     {
     9         return String.Format("{0},{1},{2}",Id,FirstName,LastName);
    10     }
    11
    12     public override bool Equals(object obj)
    13     {
    14         if(obj==null)
    15         {
    16             return base.Equals(obj);
    17         }
    18         return Equals(obj as Person);
    19     }
    20
    21     public override int GetHashCode()
    22     {
    23         return Id.GetHashCode();
    24     }
    25
    26     public bool Equals(Person other)
    27     {
    28         if(other==null)
    29         {
    30             return base.Equals(other);
    31         }
    32         return this.Id==other.Id && this.FirstName==oher.FirstName&&this.LastName==other.LastName;
    33     }
    34 }

    接下来创建了两个包含Person项的数组。这两个数组通过变量名janet 包含相同的Person对象,和两个内容相同的不同Person对象。比较运算符“!=”返回 true,因为这其实是两个变量person1 和 persons2医用的两个不同数组。因为 Array类没有重写带一个参数的Equals方法,所以用“==”运算符比较引用也会得到相同的结果,即这两个变量不相同。

  •  1 var janet =new Person{FirstName="Janet",LastName="Jackson"};
     2 Person[] persons1={
     3     new Person
     4     {
     5         FirstName="Michael",
     6         LastName="Jackson"
     7     }.
     8     janet
     9 };
    10 Person[] persons2={
    11     new Person
    12     {
    13         FirstName="Michael",
    14         LastName="Jackson"
    15     },
    16     janet
    17 };
    18 if(persons1!=persons2)
    19 {
    20     Console.WrilteLine("not the same reference!");
    21 }
时间: 2024-10-09 17:38:07

C#高级编程笔记 Day 8, 2016年9月 28日 (数组)的相关文章

软考中高项学员:2016年3月28日作业

软考中高项学员:2016年3月28日作业 一.项目沟通管理1.项目沟通管理包括哪些过程?(记)2.阻碍有效沟通的因素有哪些?3.沟通计划编制的第一步是什么?目的是什么?4.沟通管理计划包括哪些内容(8条)5.干系人沟通计划包括哪些内容?(记)6.项目例会的主要议题有哪四条?7.项目内部启动会议.外部启动会议分别要解决什么问题?8.项目总结会议的目的有哪些?9.影响项目沟通的技术因素有哪些?9.常用的四种沟通方式是什么?各有何优缺点?10.信息分发的工具和技术是什么?11.经验教训总结过结果是什么

2016年3月28日作业

软考中高项学员:2016年3月28日作业 一.项目沟通管理1.项目沟通管理包括哪些过程?(记)答:信息的生成.传递.接收.理解检查.2.阻碍有效沟通的因素有哪些?答:1.沟通双方的物理距离.2.沟通的环境因素.3.缺乏清晰的沟通渠道.4.复杂的组织结构.5.复杂的技术术语.6.有害的态度.3.沟通计划编制的第一步是什么?目的是什么?答:沟通计划编制的第一步是干系人分析,目的是得出项目的沟通的需求和方式,进而形成较为准确的沟通需求表,然后再针对需求进行计划编制.4.沟通管理计划包括哪些内容(8条)

2016年3月28日作业 项目沟通管理与合同管理

2016年3月28日作业 项目沟通管理与合同管理 一.项目沟通管理1.项目沟通管理包括哪些过程?(记)  沟通计划编制.信息分发.绩效报告.项目干系人管理. 2.阻碍有效沟通的因素有哪些?  物理距离.环境因素.缺乏清晰的沟通渠道.复杂的组织结构.复杂的技术术语.有害的态度. 3.沟通计划编制的第一步是什么?目的是什么?     沟通计划编制的第一步就是干系人分析,目的是得出项目中沟通的需求和方式,进而形成较为准确的沟通需求表,然后再针对需求进行计划编制. 4.沟通管理计划包括哪些内容(8条) 

2016年3月28日作业(项目沟通管理、项目合同管理)

2016年3月28日作业 一.项目沟通管理 1.项目沟通管理包括哪些过程?(记) 1.沟通计划的编制 2.信息分发 3.绩效报告 4.项目干系人管理 2.阻碍有效沟通的因素有哪些? 1.沟通双方的物理距离 2.沟通的环境因素 3.缺乏清晰的沟通渠道 4.复杂的组织结构 5.复杂的技术术语 6.有害的态度 3.沟通计划编制的第一步是什么?目的是什么? 沟通计划编制的第一步就是干系人分析,得出项目中沟通的需求和方式,进而形成较为准确的沟通需求表,然后再针对需求进行计划编制. 4.沟通管理计划包括哪些

大陆地区OpenStack项目Core现状(截至2016年1月28日,转载自陈沙克日志)

陈沙克 经常有朋友问,大陆地区大概有多少位OpenStack项目的Core.这个问题,现在其实不太好回答,如果需要准确统计的话.下面仅仅是一个大概估计,有遗漏的,希望朋友指出,我来补全. 文档修改历史 2016年2月2日:增加IBM的刘光亚.EMC统计有误,去掉. 2016年2月21日:增加EasyStack的Tang Chen OpenStack client core 2016年4月9日:增加了intel的Eli Qiao,海云捷迅的Li Ma,eBay的Huang Zhiteng,在上海.

传智播客 2015 刘意 Java基础-视频-笔记day27(完结)(2016年5月1日12:42:20)

day27 1.类的加载概述和加载时机 2.类加载器的概述和分类 类加载器 负责将.class文件加载到内存中,并为之生成对应的Class对象. 虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行. 类加载器的组成 Bootstrap ClassLoader根类加载器 Extension ClassLoader扩展类加载器 SysetmClassLoader系统类加载器 通过这些描述我们就可以知道我们常用的东西的加载都是由谁来完成的. 到目前为止我们已经知道把class文

崔希凡JavaWeb笔记day25-day27(2016年11月11日22:02:34)

JavaWeb的学习进入尾声,最近三个dayy做了项目,也完成了一些的基础加强 以下是本人的原创笔记 链接:http://pan.baidu.com/s/1mhUtdgc 密码:1ov4

崔希凡JavaWeb笔记day19-day21(2016年10月4日17:38:58)

难点:jdbc分页查询,以及filter的几个案例 笔记分享如下 链接:http://pan.baidu.com/s/1o8NbI3o 密码:4fnc

iPhone 第一天笔记2016年03月28日(周一)A.M iPhone开发入门

1. 切换home键:command + shift + h; 2. info.plist  Application does not run in background -> YES ****************************main****************************** 1 <font size="3">#import <UIKit/UIKit.h> 2 #import "AppDelegate.h&quo