zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    B.Icebound and Sequence
    Educational Codeforces Round 65 (Rated for Div. 2) D. Bicolored RBS
    Educational Codeforces Round 65 (Rated for Div. 2) C. News Distribution
    Educational Codeforces Round 65 (Rated for Div. 2) B. Lost Numbers
    Educational Codeforces Round 65 (Rated for Div. 2) A. Telephone Number
    Codeforces Round #561 (Div. 2) C. A Tale of Two Lands
    Codeforces Round #561 (Div. 2) B. All the Vowels Please
    Codeforces Round #561 (Div. 2) A. Silent Classroom
    HDU-2119-Matrix(最大匹配)
    读书的感想!
  • 原文地址:https://www.cnblogs.com/xiyin/p/5915688.html
Copyright © 2011-2022 走看看