《C入门经典》学习笔记集合比较和转换.docx
- 文档编号:28633371
- 上传时间:2023-07-19
- 格式:DOCX
- 页数:16
- 大小:22.42KB
《C入门经典》学习笔记集合比较和转换.docx
《《C入门经典》学习笔记集合比较和转换.docx》由会员分享,可在线阅读,更多相关《《C入门经典》学习笔记集合比较和转换.docx(16页珍藏版)》请在冰豆网上搜索。
《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运算符可以检查对象是否是给定的类型,或者是否可以转换为给定的类型
语法:
1如果
2如果
3如果
值比较
运算符重载
要重载运算符,可给类添加运算符类型成员(必须是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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C入门经典 入门 经典 学习 笔记 集合 比较 转换
![提示](https://static.bdocx.com/images/bang_tan.gif)