C# 中的范型对于很多从 C++ 转过来的程序员来说,可以说是一个天大的喜讯。 hehe ,至少笔者对于这个新特性是充满了敬仰之情。
在 C#2.0 中,匿名方法、 IEnumerable 接口和匿名方法的合作,使很多的编程任务变得非常的简单,而且写出来的程序非常的优美。
比如,我们可以写出如下的代码:
List < Book > thelib = Library .getbooks();
List < Book > found = thelib.FindAll( delegate ( Book curbook)
{
if (curbook.isbn.StartsWith( "..." ))
return true ;
return false ;
});
foreach ( Book b in found)
Console .WriteLine(b.isbn);
这段程序非常简单的展示给我们需要查找的信息,代码也非常的直接易懂。内置的数据结构给了我们强大的算法支持,不过,能不能够为自定义的类定义类似的算法呢?
比如,如果我有一个自定义的 Library 类并没有使用 List
1<book> 存储数据,而是使用某种自定义的数据结构,我能不能也让用户使用类似的语法,忽略存储细节的使用匿名委托来实现特定的算法呢?
2
3答案当然是肯定的,而且在 C# 中实现这样的功能是非常的简单。
4
5首先让我们看看 FindAll 中用到的匿名委托的原型
6
7public delegate bool Predicate <t>(T obj);
8
9很明显的,上面的代码等于注册了一个搜索的回调,而在 List 内部定义了某种遍历的机制,从而实现了一个漂亮的算法结构 Closure 。
10
11看到了这些,我们就可以定义自己的算法结构了,首先,我定义了一个如下的类
12
13public class MyVec <t>
14
15{
16
17public static MyVec <t> operator +( MyVec <t> a, T b)
18
19{
20
21a._list.Add(b);
22
23return a;
24
25}
26
27public override string ToString()
28
29{
30
31StringBuilder builder = new StringBuilder ();
32
33foreach (T a in _list)
34
35{
36
37builder.Append(a.ToString());
38
39builder.Append( "," );
40
41}
42
43string ret = builder.Remove(builder.Length - 1, 1).ToString();
44
45return ret;
46
47}
48
49public MyVec <t> findAll( Predicate <t> act)
50
51{
52
53MyVec <t> t2 = new MyVec <t>();
54
55foreach (T i in _list)
56
57{
58
59if (act(i))
60
61t2._list.Add(i);
62
63}
64
65return t2;
66
67}
68
69// this is the inner object
70
71private List <t> _list = new List <t>();
72
73}
74
75这个类中包含了一个的 List<t> 结构,主要是为了证实我们的想法是否可行,事实上,任何一个可以支持 foreach 遍历的结构都可以作为内置的数据存储对象,我们会在后面的例子中给出一个更加复杂的实现。
76
77下面是用于测试这个实验类的代码:
78
79static void Main ( string [] args)
80
81{
82
83MyVec < int > a = new MyVec < int >();
84
85a += 12;
86
87a += 15;
88
89a += 32;
90
91MyVec < int > b = a.findAll( delegate ( int x)
92
93{ if (x > 20) return true ; return false ; }
94
95);
96
97Console .WriteLine( "vection original" );
98
99Console .WriteLine(a.ToString());
100
101Console .WriteLine( "vection found" );
102
103Console .WriteLine(b.ToString());
104
105Console .ReadLine();
106
107}
108
109编译,执行,程序输出:
110
111vection original
112
11312,15,32
114
115vection found
116
11732
118
119和我们预期的完全相同。很明显的, List 内部的算法与我们预期的基本相同。
120
121Predicate <t> 仅仅是为了仿照系统的实现而采用的一个委托,事实上可以使用自己定义的任何委托作为回调的函数体。
122
123通过使用 IEnumberable 接口,可以实现对任意结构的遍历,从而对任何数据结构定义强大的算法支持。</t></t></t></t></t></t></t></t></t></t></t></t></book>