C# 2.0的特性中,有三个非常好用的特性。一是delegate关键字可以用来写匿名函数。二是有Func和Action这两个类库中的泛型委托能用来匹配函数的类型。三是captured variable,也就是匿名函数中能捕获当前运行环境中的变量,比如函数的局部变量。以下代码演示了这三个特性的使用:
protected void VerifyDeletedNodes()
{
List<IBTreeNode<T>> all_nodes = new List<IBTreeNode<T>>();
int idx;
int matchcnt = 0;
int num_leaf;
int num_nleaf;
GetAllNodes_rec(all_nodes, m_root);
if (Utility.TraceFlag) {
Console.WriteLine("Verify: all {0} nodes retrieved", all_nodes.Count);
}
all_nodes.Sort(new HashCodeComparer<IBTreeNode<T>>());
foreach (IBTreeNode<T> deldnode in m_deleted_nodes) {
idx = all_nodes.BinarySearch(deldnode, new HashCodeComparer<IBTreeNode<T>>());
if (idx >= 0) {
if (Utility.TraceFlag) {
Console.WriteLine("Verify: hash code coincidence");
}
idx = ArrayUtil.BackToFirst(all_nodes, deldnode, idx, new HashCodeComparer<IBTreeNode<T>>());
ArrayUtil.WhileEqual(all_nodes, idx, new HashCodeComparer<IBTreeNode<T>>(), delegate(IBTreeNode<T> x) { if (Object.ReferenceEquals(x, deldnode)) { matchcnt++; } });
}
/* deleted nodes do not appear in the tree */
Trace.Assert(matchcnt == 0);
/* also account them now (didn't do it on deletion) */
if (deldnode is BTreeNonLeafNode<T>) {
m_commondata.m_num_nleaf--;
} else {
Trace.Assert(deldnode is BTreeLeafNode<T>);
m_commondata.m_num_leaf--;
}
}
m_deleted_nodes.Clear();
/* BTW, we also account the number of leaf and non-leaf nodes { */
num_leaf = 0;
num_nleaf = 0;
foreach (IBTreeNode<T> noderef in all_nodes) {
if (noderef is BTreeNonLeafNode<T>) {
num_nleaf++;
} else {
Trace.Assert(noderef is BTreeLeafNode<T>);
num_leaf++;
}
}
Trace.Assert(m_commondata.m_num_nleaf == num_nleaf);
Trace.Assert(m_commondata.m_num_leaf == num_leaf);
/* } */
}
上述代码是我的BTreeDemo4.cs中的一段验证代码,其中ArrayUtil.WhileEqual<T>是一个小函数,用来从数组的一个位置开始直到数组末尾执行一个函数,它的第四个参数就是Action<T>。这里用了delegate,再捕获了matchcnt这个局部变量,使用起来就非常方便。捕获的变量的生命期是在它原本的环境和捕获它的函数委托两者中取较长者,这是由垃圾回收机制实现的。