C#入门经典(第五版)学习笔记(四)

---------------集合、比较和转换---------------

C#中的数组是作为System.Array类的实例实现的,它们是集合类(Collection Classes)中的一种类型。

集合类一般用于处理对象列表,大多通过实现System.Collections名称空间中的接口而获得的

System.Collections名称空间中的几个接口提供了基本的集合功能:

 1)IEnumerable可以迭代集合中的项。

 2)ICollection(继承于IEnumerable)可以获取集合中的项的个数,并能把项复制到一个简单的数组类型中。

 3)IList(继承于IEnumerable和ICollection)提供了集合的项列表,允许访问这些项,并提供其他一些与项列表相关的基本功能

 4)IDictionary(继承于IEnumerable和ICollection)类似于IList,但提供了可通过键值(而不是索引)访问的项列表。

System.Array类实现了IList、ICollection和IEnumerable,但不支持IList的一些更高级的功能,它表示大小固定的项列表。

数组初始化需要固定大小,ArrayList集合则不用

 Animal[] animalArray = new Animal[2];

 ArrayList animalArrayList = new ArrayList();

这个类还有两个构造函数:

 1、把现有集合作为参数复制到新实例中

 2、用一个int参数设置集合的容量,不过实际内容超过容量时会自动增加

初始化数组,需要给这个项目赋予初始化了的对象 例如:

1 Cow myCow1 = new Cow("Deirdre");
2 animalArray[0] = myCow1;
3 animalArray[1] = new Chicken("Ken");

可以用这两种方式初始化数组

对于ArrayList集合,需要用Add()方法添加新项目
例如:

1 Cow myCow2 = new Cow("Hayley");
2 animalArrayList.Add(myCow2);
3 animalArrayList.Add(new Chicken("Roy"));

在添加完项目之后,就可以用与数组相同的语法重写他们
例如:

animalArrayList[1] = new Chicken("Roy2")

Array数组和ArrayList集合都支持foreach结构来迭代
例如:

1 foreach (Animal myAnimal in animalArray)
2  {
3  }
4  foreach (Animal myAnimal in animalArrayList)
5  {
6  } 

Array数组使用Length属性获取项目的个数
例如:

int animalCount = animalArray.Length; 

ArrayList集合使用Count属性获取项目的个数

int animalCount2 = animalArrayList.Count; 

Array数组是强类型化的,可以直接使用数组的类型来存储项目
即可以直接访问项目的属性和方法
例如:
对于类型是Animal的数组,Feed()是类Animal的方法

animalArray[0].Feed();

但对于类Animal派生类的方法,就不能直接调用,需要强制转换

((Chicken)animalArray[1]).LayEgg(); 

使用Remove()和RemoveAt()方法删除项目
Remove  从 ArrayList 中移除特定对象的第一个匹配项(参数为特定对象)
RemoveAt 移除 ArrayList 的指定索引处的元素(参数为索引值) 删除项目后,会使其他项目在数组中移动一个位置
使用AddRange()和InsertRange()方法可以一次添加多个项目
AddRange 将 ICollection 的元素添加到 ArrayList 的末尾
InsertRange 将集合中的某个元素插入 ArrayList 的指定索引处。 例如:

animalArrayList.AddRange(animalArray); 

使用IndexOf()方法获取指定项目的索引值
IndexOf 返回 ArrayList 或它的一部分中某个值的第一个匹配项的从零开始的索引。
可以通过索引值直接访问选项
例如:

int iIndex =  animalArrayList.IndexOf(myCow1);
((Animal)animalArrayList[iIndex]).Feed(); 

定义集合
从System.Collections.CollectionBase这个抽象类中派生自己的集合,此类提供了集合类的许多实现方法
CollectionBase类有IEumerable、ICollection和IList接口
CollectionBase提供了两个受保护的属性,可访问存储的对象本身,分别为List和InnerList,List可以通过IList接口访问项,InnerList是用于存储项的ArrayList对象
集合类定义举例:

 1 public class Animals:CollectionBase
 2  {
 3      public void Add(Animal newAnimal)
 4      {
 5          List.Add(newAnimal);
 6      }
 7      public void Remove(Animal oldAnimal)
 8      {
 9          List.Remove(oldAnimal);
10      }
11      public Animals(){}
12  }

使用ArrayList实现代码处理对象

1 Animals animalCollection = new Animals();
2  animalCollection.Add(new Cow("Cow1"));
3  foreach(Animal myAnimal in animalCollection)
4  {
5      Console.WriteLine("{0} {1}",myAnimal.ToString(),myAnimal.Name);
6  }

不能用animalCollection[0].Feed();因为没有索引符
索引符可添加到类中,使之提供类似于数组的访问,例如:

1 public class Animals:CollectionBase
2  {
3      public Animal this[int animalIndex]
4      {
5          get{return (Animal)List[animalIndex];}
6          set{List[animalIndex] = value;}
7      }
8  }

如此即可使用上面无法使用的animalCollection[0].Feed();

关键字值集合和IDictionary

与索引的集合一样,可使用一个基类简化IDictionary接口的实现,即DictionaryBase,它也实现IEnumerable和ICollection

关键字值集合举例:

public class Animals:DictionaryBase
 {
     public void Add(string newID,Animal newAnimal)
     {
         Dictionary.Add(newID,newAnimal);
     }
     public void Remove(string animalID)
     {
         Dictionary.Remove(animalID);
     }
     public Animals(){}
     public Animal this[string animalID]
     {
         get{return (Animal)Dictionary[animalID];}
         set{Dictionary[animalID] = value;}
     }
 }

字典集合有个继承于DictionaryBase的成员Dictionary,此成员是一个IDictionary接口
使用foreach和DictionaryBase派生类可以提供DictionaryEntry结构,例如:

foreach(DictionaryEntry myEntry in animalCollection)
 {
     Console.WriteLine("{0} {1}",myEntry.Value.ToString(),((Animal)myEntry.Value).Name);
 }

如果要直接通过foreach提取Animal对象,最简单的方式是实现一个迭代器

迭代器
IEnumerable接口负责使用foreach循环,在foreach循环中,迭代集合collectionObject的过程如下:
1)调用collectionObject.GetEnumerator(),返回一个IEnumerator引用,此方法可通过IEnumerable接口的实现代码来获得,但这是可选的。
2)调用所返回的IEnumerator接口的MoveNext()方法。
3)如果MoveNext()方法返回true,就是用IEnumerator接口的Current属性获取对象的一个引用,用于foreach循环。
4)重复前面两步,知道MoveNext()方法返回false为止,此时循环停止
 所以,为了在类中进行这些操作,必须重写几个方法,跟踪索引,维护Current属性,以及执行其他一些操作。
 一个较为简单的替代方法是使用迭代器,它是一个代码块,按顺序提供了要在foreach循环中使用的所有值。一般情况下,这个代码块是一个方法,但也可以使用属性访问器和其他代码块作为迭代器。
1)如果要迭代一个类,可使用方法GetEnumerator(),其返回类型是IEnmerator
 2)如果要迭代一个类成员,例如一个方法,则使用IEnumerable
在迭代器块中,使用yield关键字选择要在foreach循环中使用的值,以下举例:

public static IEnumerable SimpleList()
 {
     yield return "string 1";
     yield return "string 2";
     yield return "string 3";
 }
 public static void test()
 {
     foreach(string item in SimpleList())
     {
         Console.WriteLine(item);
     }
     Console.ReadKey();
 }

SimpleList()就是迭代器块,迭代器块内的返回类型必须一致,否则出现错误类型转换异常。
在遇到迭代器中yield break;这个语句时,迭代器处理立即中断。

浅复制与深复制
 浅显的来说,浅复制类似于引用类型,深复制类似于值类型。
 浅复制是指源对象和复制对象共用一份实体,仅仅是引用的变量不同,相当于复制了一个快捷方式。
 深复制是指源对象和复制对象相互独立,改变其中一个对象不会对另一个造成印象,相当于复制了文件本身。
MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。深复制,即实现ICloneable接口.ICloneable可用于深复制和浅复制。
 举例说明:

public class Content
 {
     public int Val;
 }

浅复制(shallow copy)

public class ShallowCopy
 {
     public Content myContent = new Content();
     public ShallowCopy(int newVal)
     {
         myContent.Val = newVal;
     }
     public object GetCopy()
     {
         return MemberwiseClone();
     }
 }

深复制(deep copy)

public class DeepCopy:ICloneable
 {
     public Content myContent = new Content();
     public DeepCopy(int newVal)
     {
         myContent.Val = newVal;
     }
     public object Clone()
     {
         DeepCopy Cloner = new DeepCopy(myContent.Val);
         return Cloner;
     }
 } 
时间: 2024-08-09 03:06:09

C#入门经典(第五版)学习笔记(四)的相关文章

C++ Primer(第五版)学习笔记_1_标准模板库--快速入门

C++ Primer(第五版)学习笔记_1_标准模板库--快速入门 欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 标准模板库(STL)提供三种类型的组件:容器.迭代器和算法,他们都支持泛型程序设计标准. 容器主要有两类:顺序容器和关联容器.顺序容器(vector.list.deque和string等)是一系列元素的有序集合.关联容器(set.multiset.map和multimap)包含查找元素的键值. 迭代器的作用是遍历容器. STL算法库包含四类算法:排序算法.不可变序算法.变序性算法

C++ Primer 第五版学习笔记

<C++ Primer>第五版中文版学习笔记 ? C++ Primer 第五版学习笔记

C++ Primer(第五版)学习笔记_9_标准模板库_multimap多重映照容器

C++ Primer(第五版)学习笔记_9_标准模板库_multimap多重映照容器 多重映照容器multimap与map结构基本相同,但由于重复键值存在,所以multimap的元素插入.删除.查找都与map的方法不相同. 1.multimap对象创建.元素插入 插入元素时,需要使用insert()方法和类似pair<string,double>("Jack", 300.5)的元素结构.可以看到,重复的元素是按照插入的先后顺序排序的. #include <iostre

C++ Primer(第五版)学习笔记_5_标准模板库string(2)

C++ Primer(第五版)学习笔记_5_标准模板库string(2) 10.搜索string对象的元素或子串 采用find()方法可查找字符串中的第一个字符元素(char, 用单引号界定)或者子串(用双引号界定):如果查到,则返回下标值(从0开始计数),如果查不到,则返回一个很大的数string:npos(即:4294967295). #include <iostream> #include <stdio.h> #include <string> using nam

C++ Primer(第五版)学习笔记_3_标准模板库vector(2)

C++ Primer(第五版)学习笔记_3_标准模板库vector(2) 欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 6.元素的插入 insert()方法可以在vector对象的任意位置前插入一个新的元素,同时,vector自动扩张一个元素空间,插入位置后的所有元素依次向后挪动一个位置. 要注意的是,insert()方法要求插入的位置,是元素的迭代器位置,而不是元素的下标. #include <iostream> #include <vector> using namespa

C++ Primer(第五版)学习笔记_2_标准模板库vector(1)

C++ Primer(第五版)学习笔记_2_标准模板库vector(1) 欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 向量容器vector不但能像数组一样进行随机访问,还能在尾部插入元素,完全可以替代数组. 值得注意的是,vector具有内存自动管理的功能,对于元素的插入和删除,可以动态调整所占的内存空间. 容器vector的下标是从0开始的,如果vector容器的大小是n,则元素下标为0~n-1,这和数组的一样的.不一样的是,vector可以随时调整其大小. vector重要的方法有三个

C++ Primer(第五版)学习笔记_4_标准模板库string(1)

C++ Primer(第五版)学习笔记_4_标准模板库string(1) 1.创建string对象 创建一个空字符串,其长度为0 #include <iostream> #include <string> using namespace std; int main(int argc, char* argv[]) { string s; cout << s.length() << endl; return 0; } 运行结果: 0 2.给string对象赋值

C++ Primer(第五版)学习笔记_6_标准模板库_set集合容器

C++ Primer(第五版)学习笔记_6_标准模板库_set集合容器 Set集合容器实现了红黑树(Red-BlackTree)的平衡二叉检索树的数据结构,在插入元素时,它会自动调整二叉树的排序,把该元素放到适当的位置. (1)确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值: (2)另外,还得确保根节点左子树的高度与右子树的高度相等.这样,二叉树的高度最小,从而检索速度最快. 平衡二叉检索树的检索使用中序遍历算法,检索效率高.默认情况下,将键值由小到大遍历. 对于s

C++ Primer(第五版)学习笔记_8_标准模板库_map映照容器

C++ Primer(第五版)学习笔记_8_标准模板库_map映照容器 map映照容器的元素数据是由一个键值和一个映照数据组成的,键值与映照数据之间具有一一映照的关系. map映照容器的数据结构也是采用红黑树来实现的. 1.map创建.元素插入和遍历访问 #include <iostream> #include <stdio.h> #include <vector> #include <map> #include <string> using n

C++ Primer(第五版)学习笔记_7_标准模板库_multiset多重集合容器

C++ Primer(第五版)学习笔记_7_标准模板库_multiset多重集合容器 多重集合容器multiset与set一样,也是使用红黑树来组织元素数据的,唯一不用的是,multiset允许重复的元素键值插入.其结构示意图如下: 1.multiset元素插入 #include <iostream> #include <stdio.h> #include <vector> #include <set> #include <string> usi