数组: 数组 ,他可以存储相同类型的固定数量的数据,可以通过索引取得相应的值。
如果存储的是值类型的话:比如 int[] arr=new int[2]; 那么变量arr 在栈上 ,他引用 两个 托管堆上的 int 值。
如果存储的是引用类型:比如 Person[] arr=new Person[2]; 那么 变量 arr、在栈上,这个变量引用了 用来存储 托管堆上person类的引用的数组。
Array 类: 是一个抽象类,他实现了 ICloneable, IList, ICollection, IEnumerable 这几个接口
拷贝:
而ICloneable 实现了Clone() 他是创建一个浅表层的副本: 如果是 值类型,他复制的东西是 所有的值。 如果是应用类型,它复制的是 引用,新的数组操作的 还是 同一个内存。
Copy 同样是浅拷贝,区别就是:Clone 直接创建一个新的数组,Copy 要有相同维数 , 和足够多的容量 存储拷贝。
需要深拷贝 引用类型数组的话, 要迭代 数组创建新的对象。
排序: Array 类使用 快排算法 对数组中的元素进行排序, Sort()方法要求 数组中的元素实现IComparable接口 。Array.Sort(strings),简单类型String int32 实现了这个借口。
IComparable接口一个 CompareTo() ,要使用sort() 要实现它,相等返回 0 , 如果 实例排在参数 前面 方法返回小于0的数, 实例排在参数后面 返回大于 0 的参数。 如果 要实现别的排序方式 可以实现 IComPare接口 ,和或 Icompare<T> 接口, IcomPare类独立于 要比较的类 这样就可以通过 Array.Sort(persons,new PersonCompare)进行比较了.
IEunmerator 接口: 枚举接口,GetEnumerator()方法 ,返回一个实现 IEunmerator 接口的的 枚举,他定义了了
bool MoveNext();
object Current { get; }
void Reset();
三个方法。
foreach 使用了 枚举
而使用 yield 迭代 会方便创建 枚举器,
public class Gge
{//实现
GetEnumerator()
public IEnumerator<String> GetEnumerator() { yield return 9; yield return 6; } }
就可以使用foreach 迭代 Gge了。
包含 yield 语句的 方法 或 属性 称为 迭代块 必须返回 IEnumerator、或Ienumerable 接口 ,编译时yield语句会生成一个枚举器。
通过使用 yield 定义迭代器,可在实现自定义集合类型的 IEnumerable 和IEnumerator 模式时无需其他显式类(保留枚举状态的类,有关示例,请参阅IEnumerator<T>)。
public class PowersOf2 { static void Main() { // Display powers of 2 up to the exponent of 8: foreach (int i in Power(2, 8)) { Console.Write("{0} ", i); } } public static System.Collections.Generic.IEnumerable<int> Power(int number, int exponent) { int result = 1; for (int i = 0; i < exponent; i++) { result = result * number; yield return result; } } // Output: 2 4 8 16 32 64 128 256 }
使用 迭代块 编译器会生成 一个yield 类型,其中包含一个状态机、、待完善。
集合 : 数组大小是固定的 , 如果要 要存储动态元素个数 就要使用集合。集合类 有List<T> ,队列 ,栈, 链表 ,字典 ,集。 分泛型类集合有 ArrayList HashTable. 线程安全的集合类 位于 System.Conllection.Concurrent。
动态列表有List<T > 实现了 IList , ICollection, IEnumerable , IList<T> , ICollection<T>、IEnumerable<T>,而 ArrayList是 一个非泛型 列表。 List<T> 默认 构造 一个空列表 ,添加元素后 会构建 4个元素,如过超过了的话 容量会 ,扩展倒两倍。如果容量改变 ,内容就会重新分配到新的内存中。创建新的数组,通过Array.Copy(). 所以事先知道他的 容量的话,给定容量 ,效率会更高。
有 初始值设定 ,添加元素 ,插入元素,访问元素,删除元素,收索,排序,类型转换,只读集合。
队列:队列 先进先出,Queue<T> 实现了 ICollection 和 IEnumerable <T> 接口 没有实现 IConllection<T> 接口,add remove 方法不能用于队列。 也没有实现IList<T>接口,不能用索引器访问队列。内部用 T[] 实现。待续
栈 : 先进 后出的结构,在foreach 方法中 ,IEnumerable接口迭代所有元素,栈的枚举器不会删除元素。
链表: 带续
字典: 字典是个很复杂的数据结构,它能根据键,快速查找值。也可以自由添加 和 删除元素。 有点像List<T>,但没有内存中移动后续元素的性能 开销。
作为字典中键的类型必须重写Object类的 GetHashCode() 方法,因为字典要确定元素的位置,他要调用GetHashCode() 返回的int来计算在对应位置放置的元素索引。它涉及素数,字典的容量是一个素数。 字典的新能取决于GetHashCode()的代码。
键类型还需要重写IEquatable<T>.Equals()方法。或重写Object的Equals() 方法。 如果A.Equals(B)返回true ,则 A.GetHashCode() 和 B.GetHashCode(); 如果设计出的某种重写这些方法的方式不满足 这个条件,而把它作为键的话,就会出现索引不到值的现象。
Equals方法 比较的是引用,,GetHashCode()返回的是一个仅基于对象地址的散列代码。如果 散列表基于一个键 ,而建没有重写这些方法,这个散列表就能 正常工作。 但是这么做 只有 对象完全相同,键才被认为是相等的。
String实现了IEquatable 接口,并重载了 GetHashCode() 方法,Equals()提供了值的比较,GEtHashCode() 根据字符串的值返回一个散列表代码。 字典中用字符串作为 键值很方便。
int32并不适合在字典中使用。 这些类型的返回 散列代码 只映射 到值上。 如果希望用作键的数值 本身没有分布在 可能的整数范围内,把整数作为键值就不好了。