CH 11

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

  • IEnumerable可以迭代集合中的项。
  • ICollection(继承于IEnumerable)可以获取集合中的项的个数,并能把项复制到一个简单的数组类型中。
  • IList(继承于IEnumerableICollection)提供了集合的项列表,允许访问这些项,并提供其他一些与项列表的相关的基本功能。
  • IDictionary(继承于IEnumerableICollection)类似于IList,但提供了可通过键值访问的项列表。

System.Array类实现了IListICollectionIEnumerable,表示大小固定的项列表。

System.Collections.ArrayList类实现了IListICollectionIEnumerable,表示大小可变的项列表。

System.Collections.CollectionBase; System.Collections.DictionaryBase

foreach循环中,迭代一个collectionObject集合的过程如下:

  1. 调用collectionObject.GetEnumerator(),返回一个IEnumerator引用。这个方法可以通过IEnumerator接口的实现代码来获得,但是可选。
  2. 调用所返回的IEnumerator接口的MoveNext()方法。
  3. 如果MoveNext()方法返回true,就使用IEnumerator接口的Current属性来获取对象的一个引用。
  4. 重复2、3直到MoveNext()返回false为止,此时循环停止。

迭代器: 一个代码块,顺序提供了要在foreach循环中使用的所有值。

  • 如果要迭代一个类,使用方法GetEnumerator(),返回类型是IEnumerator
  • 如果要迭代一个类成员,例如一个方法,则使用IEnumerable

yield

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public 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
31
public 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
3
A 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
13
public 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()

IComparableIComparer接口

  • 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
29
public 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
19
public 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>类型中。