《C入门经典》学习笔记集合比较和转换.docx

上传人:b****5 文档编号:28633371 上传时间:2023-07-19 格式:DOCX 页数:16 大小:22.42KB
下载 相关 举报
《C入门经典》学习笔记集合比较和转换.docx_第1页
第1页 / 共16页
《C入门经典》学习笔记集合比较和转换.docx_第2页
第2页 / 共16页
《C入门经典》学习笔记集合比较和转换.docx_第3页
第3页 / 共16页
《C入门经典》学习笔记集合比较和转换.docx_第4页
第4页 / 共16页
《C入门经典》学习笔记集合比较和转换.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

《C入门经典》学习笔记集合比较和转换.docx

《《C入门经典》学习笔记集合比较和转换.docx》由会员分享,可在线阅读,更多相关《《C入门经典》学习笔记集合比较和转换.docx(16页珍藏版)》请在冰豆网上搜索。

《C入门经典》学习笔记集合比较和转换.docx

《C入门经典》学习笔记集合比较和转换

《C#入门经典》学习笔记(集合、比较和转换)

集合

 C#中的数组是作为System.Array类的实例来执行的,它们是集合类中的一种

集合类一般用于处理对象列表,其功能是通过执行System.Collection中的接口实现的

集合的功能可以通过接口来实现

该接口可以使用基本基本集合类,也可以创建自定义的集合类

System.Collections命名空间有很多接口提供了基本的集合功能:

IEnumerable:

公开枚举数,该枚举数支持在非泛型集合上进行简单迭代

ICollection:

定义所有非泛型集合的大小、枚举数和同步方法

IList:

表示可按照索引单独访问的对象的非泛型集合

IDictionary:

表示键/值对的非通用集合

System.Array类继承了IList,ICollection和IEnumerable

但不支持IList的一些高级功能,而且是一个大小固定的项目列表

使用集合

Systems.Collections中的一个类System.Collections.ArrayList,也执行IList,ICollection和IEnumerable接口,但与数组不同,它是大小可变的

使用System.Array类的集合(数组),必须用固定的大小来初始化数组

例如:

Animal[]animalArray=newAnimal[2];

使用System.ArrayList类的集合,不需要初始化其大小

例如:

ArrayListanimalArrayList=newArrayList();

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

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

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

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

例如:

CowmyCow1=newCow("Deirdre");

animalArray[0]=myCow1;

animalArray[1]=newChicken("Ken");

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

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

例如:

CowmyCow2=newCow("Hayley");

animalArrayList.Add(myCow2);animalArrayList.Add(newChicken("Roy"));

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

例如:

animalArrayList[1]=newChicken("Roy2")

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

例如:

foreach(AnimalmyAnimalinanimalArray)

{

}

foreach(AnimalmyAnimalinanimalArrayList)

{

}

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

例如:

intanimalCount=animalArray.Length;

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

intanimalCount2=animalArrayList.Count;

Array数组是强类型化的,可以直接使用数组的类型来存储项目

即可以直接访问项目的属性和方法

例如:

对于类型是Animal的数组,Feed()是类Animal的方法

animalArray[0].Feed();

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

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

ArrayList集合是System.Object对象的集合,通过多态性赋給Animal对象

必须进行数据类型转换

例如:

((Animal)animalArrayList[0]).Feed();

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

使用Remove()和RemoveAt()方法删除项目

Remove  从ArrayList中移除特定对象的第一个匹配项(参数为特定对象)

RemoveAt 移除ArrayList的指定索引处的元素(参数为索引值)

删除项目后,会使其他项目在数组中移动一个位置

使用AddRange()和InsertRange()方法可以一次添加多个项目

AddRange 将ICollection的元素添加到ArrayList的末尾

InsertRange 将集合中的某个元素插入ArrayList的指定索引处。

例如:

animalArrayList.AddRange(animalArray);

使用IndexOf()方法获取指定项目的索引值

IndexOf 返回ArrayList或它的一部分中某个值的第一个匹配项的从零开始的索引。

 

可以通过索引值直接访问选项

例如:

intiIndex= animalArrayList.IndexOf(myCow1);

((Animal)animalArrayList[iIndex]).Feed();

定义集合

可以从一个类派生自定义的集合

推荐使用System.Collections.CollectionBase类

CollectionBase类有接口IEnumerable,ICollection,和IList

List属性可以通过Ilist接口访问项目,InnerList属性用于存储项目的ArrayList对象

例如:

publicclassAnimals:

CollectionBase

{

   publicvoidAdd(AnimalnewAnimal)

   {

       List.Add(newAnimal);

   }

   publicvoidRemove(AnimaloldAnimal)

   {

       List.Remove(oldAnimal);

   }

   publicAnimals()

   {

   }

}

这个类用于生成Animal类型的集合,可以用foreach访问其成员:

AnimalsanimalCollection=newAnimals();

animalCollection.Add(newCow("Sarah"));

foreach(AnimalmyAnimalinanimalCollection)

{

}

如果要以索引的方式访问项目,就需要使用索引符

索引符

索引符是一种特殊类型的属性,可以把它添加到类中,提供类似数组的访问

最常见的一个用法是对项目执行一个数字索引

例如:

在Animals集合中添加一个索引符publicclassAnimals:

CollectionBase

{

   ...

   publicAnimalthis[intanimalIndex]

   {

       get

       {

           return(Animal)List[animalIndex];

       }

       set

       {

           List[animalIndex]=value;

       }

   }

}

this关键字与方括号一起,方括号中是索引参数

对List使用一个索引符,而且显示声明了类型,因为IList接口返回的是System.Object对象

现在可以用索引的方式访问项目:

animalCollection[0].Feed();

关键字值集合和IDictionary

集合还可以执行类似的IDictionary接口,通过关键字值进行索引

使用基类DictionaryBase,它也执行IEnumerable和ICollection接口,提供了对任何集合都相同的集合处理功能

例如:

publicclassAnimals:

DictionaryBase

{

   publicvoidAdd(stringnewID,AnimalnewAnimal)

   {

       Dictionary.Add(newID,newAnimal);

   }

   publicvoidRemove(stringanimalID)

   {

       Dictionary.Remove(animalID);

   }

   publicAnimals()

   {

   }

   publicAnimalthis[stringanimalID]

   {

       get

       {

           return(Animal)Dictionary[animalID];       }

       set

       {

           Dictionary[animalID]=value;

       }

   }

}

这样添加了Add()方法,Remove()方法和一个通过关键字访问项目的方法

其中Dictionary是包含在DictionaryBase实例中的元素的列表

DictionaryBase集合和CollectionBase集合在foreach的工作方式不同,

DictionaryBase提供的是DictionaryEntry结构,需要通过Value成员获取对象本身

例如:

CollectionBase集合:

foreach(AnimalmyAnimalinanimalCollection)

{

  myAnimal.Feed();

}

DictionaryBase集合:

foreach(DictionaryEntrymyEntryinanimalCollection)

{

  ((Animal)myEntry.Value).Feed();

}

迭代器

通过IEnumerable接口,可以使用foreach循环获取对象

foreach循环,迭代collectionObject的过程:

1调用Collection的GetEnumerator()方法返回一个IEnumerator引用

 该方法也可以通过IEnumerable接口的实现代码获得

2调用IEnumerator接口的MoveNext()方法,将枚举数推进到集合的下一个元素

3如果MoveNext()方法返回true,使用IEnumerator接口的Current属性获取对象的引用,用于foreach循环

4重复前两个步骤,直至MoveNext()返回false时,循环停止

迭代器是一个按顺序提供要在foreach循环中使用的所有值的代码块

一般这个代码块是一个方法,也可以使用属性访问器和其他代码块作为迭代器

代码块的返回值可能是IEnumerable或IEnumerator接口类型:

1如果要迭代一个类,可使用方法IEnumerator(),其返回类型是IEnumerator

2如果要迭代一个类成员,则使用IEnumerable

在迭代器块中,使用yield关键字选择要在foreach循环中使用的值

语法:

yieldreturnvalue;

例如:

publicstaticIEnumerableSimpleList()

{

   yieldreturn"string1";

   yieldreturn"string2";   yieldreturn"string3";

}

publicstaticvoidMain(string[]args)

{

   foreach(stringiteminSimpleList())

       Console.WriteLine(item);

   Console.ReadKey();

}

这里SimpleList就是迭代器块,是一个方法,使用IEnumerable返回类型

可以从yield语句中返回任意类型

可以中断信息返回foreach循环过程

语法:

yieldbreak;

迭代器和集合

迭代器可以用于迭代储存在目录类型的集合中的对象

例如:

publicnewIEnumeratorGetEnumerator()

{

   foreach(objectanimalinDictionary.Values)

       yieldreturn(Animal)animal;

}

迭代集合中的对象:

foreach(AnimalmyAnimalinanimalCollection)

{

}

深度复制

使用System.Object.MemberwiseClone()方法可以进行阴影复制

对于值类型成员,没什么问题

但对于引用类型成员,新对象和源对象的成员将指向同一个引用对象

例如:

publicclassContent

{

  publicintVal;

}

  

publicclassCloner

{

  publicContentMyContent=newContent();

  

  publicCloner(intnewVal)

  {

     MyContent.Val=newVal;

  }

  publicobjectGetCopy()

  {

     returnMemberwiseClone();

  }

}

执行:

ClonermySource=newCloner(5);

ClonermyTarget=(Cloner)mySource.GetCopy();

intiVal1=myTarget.MyContent.Val;

mySource.MyContent.Val=2;

intiVal2=myTarget.MyContent.Val;

结果:

iVal1是5,iVal2是2

但有时候需要的是分别引用各自的对象,使用深度复制就可以解决

标准方式是添加一个ICloneable接口,该接口有一个Clone()方法

该方法不带参数,返回一个对象类型

例如:

publicclassContent

{

  publicintVal;

}

  

publicclassCloner:

ICloneable

{

  publicContentMyContent=newContent();

  publicintiVal=0;

  

  publicCloner(intnewVal)

  {

     MyContent.Val=newVal;

  }

  

  publicobjectClone()

  {

     ClonerclonedCloner=newCloner(MyContent.Val);

     clonedCloner.iVal=iVal;

     returnclonedCloner;

  }

}

通过Cloner对象的Val字段创建一个相同的Cloner对象

如果有值成员需要复制,那必须给新对象添加上这个成员

这样就能复制一个与源对象相同而互相独立的新对象

用GetCopy换成Clone,执行相同的程序,结果:

iVal1是5,iVal2是5

 

比较

类型比较

 

比较对象时,需要先知道对象的类型,可以使用GetType()方法

配合typeof()运算符一起使用,就可以确定对象的类型

if(myObj.GetType()==typeof(MyComplexClass))

{

  //myObjisaninstanceoftheclassMyComplexClass.

}

封箱和拆箱

处理值类型时后台的操作:

封箱(boxing)是把值类型转换为System.Object类型或由值类型实现的接口类型

拆箱(unboxing)是相反的过程

例如:

结构类型:

structMyStruct

{

   publicintVal;

}

把类型结构放在object类型变量中封箱:

MyStructvalType1=newMyStruct();

valType1.Val=5;

objectrefType=valType1;

这里创建了一个MyStruct类型的valType1,给成员赋值后封箱到对象refType中

这种方式的封装,将包含值类型的一个副本的引用,而不是源值的引用

验证:

valType1.Val=6;

MyStructvalType2=(MyStruct)refType;

结果valType2.Val是5而不是6

如果对个引用类型进行封装,将包含源值的引用

例如:

classMyStruct

{

  publicintVal;

}

执行相同的操作,得到valType2.Val的值是6

可以把值类型封箱到一个接口类型中:

interfaceIMyInterface{

}

  

structMyStruct:

IMyInterface

{

  publicintVal;

}

把结构封箱到IMyInterface类型中:

MyStructvalType1=newMyStruct();

IMyInterfacerefType=valType1;

拆箱:

MyStructValType2=(MyStruct)refType;

封箱是在没有用户干涉的情况下进行的

拆箱一个值需要进行显式转换(封箱是隐式的转换)

访问值类型的内容前,必须进行拆箱

is运算符

is运算符可以检查对象是否是给定的类型,或者是否可以转换为给定的类型

语法:

is

1如果是一个类类型,也是该类型,或继承了该类型,或封箱到该类型中,则返回true

2如果是一个接口类型,也是该类型,或是实现该接口的类型,则返回true

3如果是一个值类型,也是该类型,或封箱到该类型中,则返回true

值比较

运算符重载

要重载运算符,可给类添加运算符类型成员(必须是static)

例如:

重载+运算符:

Code

运算符重载与标准静态方法声明类似,但它使用关键字operator和运算符本身

使用:

Code

结果op3.val的值是9

注意:

如果混合了类型,操作数数序必须与运算符重载参数顺序相同

可以重载的运算符:

一元运算符:

+,-,!

,~,++,--,true,false

二元运算符:

+,-,*,/,%,&,|,^,<<,>>

比较运算符:

==,!

=,<,>,<=,>=

注意:

如果重载true或false运算符,可以在布尔表达式中使用类,例如if(op1){}

运算符如<和>必须成对重载,但可以使用其他运算符来减少代码

例如:

Code

 同时适用于==和!

=,常常需要重写Object.Equals()和Object.GetHashCode()

Code

IComparable和IComparer接口

IComparable和IComparer接口是比较对象的标准方式

区别:

IComparable在要比较的对象的类中实现,可以比较该对象和另一个对象

IComparer在一个单独的类中实现,可以比较任意两个对象

.NetFramework在类Comparer上提供了IComparer接口的默认实现方式,类Comparer位于System.Collections命名空间中,可以对简单类型以及支持IComparable接口的任意类型进行特定文化的比较

public class SamplesComparer{    public static void Main()    {        String str1 = "llegar";        String str2 = "lugar";        Console.WriteLine("Comparing \"{0}\" and \"{1}\" 

", str1, str2);        // Uses the DefaultInvariant Comparer.        Console.WriteLine("   Invariant Comparer:

 {0}", Comparer.DefaultInvariant.Compare(str1, str2));        // Uses the Comparer based on the culture "es-ES" (Spanish - Spain, international sort).        Comparer myCompIntl = new Comparer(new CultureInfo("es-ES", false));        Console.WriteLine("   International Sort:

 {0}", myCompIntl.Compare(str1, str2))    }}

一般使用IComparable给出类的默认比较代码,使用其他类给出非默认的比较代码

IComparable提供一个CompareTo()方法比较两个对象,并返回一个int值

例如:

    class Person :

 IComparable    {        public string Name;        public int Age;        public Person(string name, int age)        {            Name = name;            Age = age;        }        public int CompareTo(object obj)        {            if (obj is Person)            {                Person otherPerson = obj as Person;                return this.Age - otherPerson.Age;            }            else            {                throw new ArgumentException( "Object to compare to is not a Person object.");            }        }    }

主程序代码

    class Program    {        static vo

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1