Abstract
C# 1.0提出了Delegate取代C/C++的function pointer後,C# 2.0提出了Anonymous methods,C# 3.0提出了Action Generic Delegate與Lambda expressions,我們來看看這些新的技術如何取代function pointer?
Introduction
使用環境:Visual Studio 2008 + .NET Framework 3.5 + C# 3.0
C的Function Pointer
在C的時代,若要將function當成引數傳到另外一個function,靠的就是function pointer這個必殺技。
function_pointer.c / C
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : function_pointer.v
5 Compiler : Visual Studio 2008
6 Description : function pointer by C
7 Release : 02/12/2011 1.0
8 */
9
10 #include <stdio.h>
11 #include <string.h>
12
13 typedef void (*fptr)(char *s); // function pointer
14 void write_to_console(char *s);
15 void write_to_file(char *s);
16 void display_message(fptr m, char *s);
17
18 int main() {
19 int i;
20 char s[] = "Hello World";
21 fptr m;
22
23 printf("1:write to console, 2:write to text\n");
24 i = getchar();
25
26 if (i == 49) // ASCII : 1
27 m = write_to_console;
28 else
29 m = write_to_file;
30
31 display_message(m, s); // use function pointer to pass a function
32 }
33
34 void write_to_console(char *s) {
35 printf("%s\n", s);
36 }
37
38 void write_to_file(char *s) {
39 FILE *fp;
40 fp = fopen("test.txt", "w");
41 fwrite(s, strlen(s), 1, fp);
42 fclose(fp);
43 }
44
45 void display_message(fptr m, char *s) {
46 (*m)(s); // use function pointer to call function
47 }
13行
定義一個function pointer型別fptr,該function為回傳void,傳入為char *。
21行
使用剛定義的ftpr型別定義一個function pointer m。
27行
將一個function指定給該function pointer。
31行
將該function pointer傳進display_message()這個function,在此我們首次將function變成引數,透過function pointer的方式傳進一個function,這也是function pointer的主要功能。
46行
m為一個function pointer,故需要使用(*m)變成一個function使用,之後再傳入該function的引數。
C# 1.0的Delegate
C#是個OOP,所以將function pointer變成Delegate Object,以前在C是要傳遞pointer,現在在C#是要傳遞object。
use_delegate.cs / C#
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : use_delegate.cs
5 Compiler : Visual Studio 2008
6 Description : delegate by C# 1.0
7 Release : 02/12/2011 1.0
8 */
9
10 using System;
11 using System.IO;
12
13 delegate void display_method(string s); // declare delegate class type
14
15 class use_delegate {
16 static void Main(string[] args) {
17 Console.WriteLine("1:write to console, 2:write to text");
18 int i = Console.Read();
19 string s = "Hello World";
20
21 display_method m; // instantiate delegate object m
22 if (i == 49) // ACSII 1
23 m = write_to_console; // assign method to delegate object
24 else
25 m = write_to_file;
26
27 display_message(m, s); // use delegate to pass a method
28 }
29
30 static void write_to_console(string s) {
31 Console.WriteLine(s);
32 }
33
34 static void write_to_file(string s) {
35 using (StreamWriter sw = new StreamWriter("test.txt"))
36 sw.WriteLine(s);
37 }
38
39 static void display_message(display_method m, string s) {
40 m(s); // use delegate to call method
41 }
42 }
13行
定義一個delegate型別display_method,該delegate為回傳void,傳入char *。
21行
使用剛定義的display_method delegate建立一個m delegate object。
23行
將1個method指定給該delegate object。
27行
將該delegate object傳進display_message()這個method,在此我們首次看到C# 1.0利用delegate將method變成引數,透過delegate object的方式傳進一個method。
40行
m已經是一個object,故可以直接傳入引數。
在此我們可以看到C# 1.0的delegate成功地隱藏了function pointer的那顆pointer,C最難學的就是pointer,後來的語言幾乎都使用compiler的力量,用各種syntax sugar去隱藏pointer,C#也不例外,其實C這段程式碼幾乎與C#完全相同,只是將function pointer改成delegate而已。
C# 2.0的Anomymous Method
anonymous_method.cs / C#
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : anonymous_method.cs
5 Compiler : Visual Studio 2008
6 Description : anonymous method by C# 2.0
7 Release : 02/12/2011 1.0
8 */
9
10 using System;
11 using System.IO;
12
13 delegate void display_method(string s); // declare delegate class type
14
15 class anonymous_method {
16 static void Main(string[] args) {
17 Console.WriteLine("1:write to console, 2:write to text");
18 int i = Console.Read();
19 string s = "Hello World";
20
21 display_method m; // instantiate delegate object m
22
23 if (i == 49)
24 m = delegate(string t) { // anonymous method
25 Console.WriteLine(t);
26 };
27 else
28 m = delegate(string t) { // anomymous method
29 using (StreamWriter sw = new StreamWriter("test.txt"))
30 sw.WriteLine(t);
31 };
32
33 display_message(m, s);
34 }
35
36 static void display_message(display_method m, string s) {
37 m(s);
38 }
39 }
24行
Console.WriteLine(t);
};
使用了anonymous method定義要指定給delegate的method實質內容,其實anonymous method已經有lambda的味道,主要是在解決以往OOP中,總是要為一些只有一兩行code的東西另開一個method的困擾,這在C++使用STL時更可以明顯的發現這種困擾,C# 2.0在此整個架構仍使用delegate,只是加上anonymous method讓整體更精簡。
C# 3.0的Action<T> Generic Delegate與Lambda
use_lambda.cs / C#
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : use_lambda.cs
5 Compiler : Visual Studio 2008
6 Description : function pointer by C# 3.0
7 Release : 02/12/2011 1.0
8 */
9
10 using System;
11 using System.IO;
12
13 class use_lambda {
14 static void Main(string[] args) {
15 Console.WriteLine("1:write to console, 2:write to text");
16 int i = Console.Read();
17 string s = "Hello World";
18
19 Action<string> m; // Action<T> generic delegate
20
21 if (i == 49)
22 m = t => Console.WriteLine(t); // lambda
23 else
24 m = t => { // lambda
25 using (StreamWriter sw = new StreamWriter("test.txt"))
26 sw.WriteLine(t);
27 };
28
29 display_message(m, s);
30 }
31
32 static void display_message(Action<string> m, string s) {
33 m(s);
34 }
35 }
19行
C# 3.0提出了Action<T>,簡單的說就是將delegate也泛型化,讓你不用在自己宣告delegate type,直接要用就可以用,另外還有Func<TResult>,有興趣請參考MSDN Func<TResult> Delegate。
22行
C# 3.0終於提出了Lambda取代了Anonymous Method,我自己其實還蠻喜歡C# 3.0的Lambda,綜觀各種語言的Lambda,就屬C# 3.0的Lambda最帥,最乾淨俐落。
在C# 3.0已經看不到delegate,而是用Action<T>與Func<TResult>這種泛型的delegate取代,另外加上Lambda之後,讓整個Delegate更為完整。
完整程式碼下載
function_pointer.7z (使用C的function pointer)
use_delegate.7z (使用C# 1.0的delegate)
anonymous_method.7z (使用C# 2.0的anonymous method)
use_lambda.7z (使用C# 3.0的Action<T>與Lambda)
Conclusion
本文使用了MSDN Action<T> Delegate所提出的範例加以修改,並加上C的function pointer版本做比對,作為學習Action<T> Generic Delegate的一個紀錄。
C++的function pointer解決方案為Function Object,請參考(原創) Function Pointer、Delegate和Function Object (C/C++) (template) (.NET) (C#) 。
目前看起來,C、C++、C#的解決方案中,屬C# 3.0的Action<T>與Lambda最好,最簡潔也最直觀。
使用過這麼多語言,只有兩個語言是真的讓我打從心裡喜歡,一個是C語言,一個是C#。
喜歡C語言的原因是它是個小語言,也因為小,所以在各個平臺都有完整實作,是一個真正的跨平臺語言,而且它很少有Compiler動手腳,可以讓你完整掌握,雖然pointer讓我們又愛又恨,有很高的學習門檻,但只要搞清楚,C是一個很好掌握的語言。
喜歡C#語言的原因是他語法實在乾淨漂亮,一整個看起來就是舒服,不像Java那樣囉唆,也不像C++那樣繁瑣,寫起程式的感覺如行雲流水,非常爽快。
Reference
MSDN Action<T> Delegate
MSDN Func<TResult> Delegate
See Also
全文完。