C#入门经典 Part 3
Contents
CH 11
System.Collections名空间中的几个接口提供了基本的集合功能:
IEnumerable可以迭代集合中的项。ICollection(继承于IEnumerable)可以获取集合中的项的个数,并能把项复制到一个简单的数组类型中。IList(继承于IEnumerable和ICollection)提供了集合的项列表,允许访问这些项,并提供其他一些与项列表的相关的基本功能。IDictionary(继承于IEnumerable和ICollection)类似于IList,但提供了可通过键值访问的项列表。
System.Array类实现了IList、ICollection和IEnumerable,表示大小固定的项列表。
System.Collections.ArrayList类实现了IList、ICollection和IEnumerable,表示大小可变的项列表。
System.Collections.CollectionBase; System.Collections.DictionaryBase
在foreach循环中,迭代一个collectionObject集合的过程如下:
- 调用
collectionObject.GetEnumerator(),返回一个IEnumerator引用。这个方法可以通过IEnumerator接口的实现代码来获得,但是可选。 - 调用所返回的
IEnumerator接口的MoveNext()方法。 - 如果
MoveNext()方法返回true,就使用IEnumerator接口的Current属性来获取对象的一个引用。 - 重复2、3直到
MoveNext()返回false为止,此时循环停止。
迭代器: 一个代码块,顺序提供了要在foreach循环中使用的所有值。
- 如果要迭代一个类,使用方法
GetEnumerator(),返回类型是IEnumerator。 - 如果要迭代一个类成员,例如一个方法,则使用
IEnumerable。
yield1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public static IEnumerable SimpleList()
{
yield return "a";
yield return "b";
yield return "c";
}
static void main(string[] args)
{
foreach(string str in SimpleList())
{
// ...
}
}
///
public class A
{
public IEnumerator GetEnumerator()
{
yield return ...;
}
}
浅复制和深复制1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31public class A
{
// ...
public object GetCopy()
{
return MemberwiseClone(); // 浅复制
}
}
///
public class Content
{
public int Val;
}
public class Cloner: ICloneable // 深复制
{
public Content MyContent = new Content();
public Cloner(int newVal)
{
MyContent.Val = newVal;
}
public object Clone()
{
Cloner clonedCloner = new Cloner(MyContent.Val);
return clonedCloner;
}
}
封箱 & 拆箱1
2
3A a1 = new A();
object obj = a1;
A a2 = (A)obj;
is运算符: 检查对象是不是给定类型,或者是否可以转换为给定类型,如果是,这个运算符就返回true。1
<operand> is <type>
运算符重载1
2
3
4
5
6
7
8
9
10
11
12
13public static A operator +(A a1, A a2) // 双目操作符
{
A ret = new A();
// ...
return ret;
}
public static A opertor -(A a) // 单目操作符
{
A ret = new A();
// ...
reutrn ret;
}
- 不要把签名相同的运算符添加到多个类中。
- 如果混合了类型,操作数的顺序必须与运算符重载的参数顺序相同。
- 不能重载赋值运算符。
- 一些运算符(如
<和>)必须成对重载。 - 对于
==和!=,通常需要重写public override bool Equals(object op1)和public override int GetHashCode()。
IComparable和IComparer接口
IComparable在要比较的对象的类中实现,可以比较该对象和另一个对象。IComparer在一个单独的类中实现,可以比较任意两个对象。
Comparer: IComparer接口的默认实现,可以对简单类型以及支持IComparable接口的任意类型进行特定文化(不同国家语言的比较方式?)的比较,Comparer.Default.Compare(a, b)。
对实现了IComparer接口的类对象list进行排序1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29public class Person: IComparable
{
// ...
public int CompareTo(object obj)
{
// ...
}
}
public class PersonComparer: IComparer
{
public static PersonComparer Default = new PersonComparer();
public int Compare(object a, object b)
{
if(a is Person && b is Person)
{
return Comparer.Default.Compare(((Person)a).Name, ((Person)b).Name);
}
// ...
}
}
ArrayList list = new ArrayList();
list.Add(new Person(/* ... */));
// ...
list.Sort(); // 调用Person类中的CompareTo()方法,Person类实现了IComparable
list.Sort(PersonComparer.Default);
重载转换运算符1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class A
{
public static implicit operator B(A a) // 隐式类型转换
{
B b = new B();
// ...
return b;
}
}
public class B
{
public static explicit operator A(B b) // 显式类型转换
{
A a = new A();
// ...
return a;
}
}
as运算符: 把一种类型转换为指定的引用类型,如果不能转换,表达式结果为null。1
<operand> as <type>
适用情况:
<operand>的类型是<type>类型;<operand>可以隐式转换为<type>类型;<operand>可以封箱到<type>类型中。