C# 委托
C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。
委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。
一、声明委托(Delegate)
委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。
例如,假设有一个委托:
1 2 |
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">delegate</span> <span class="hljs-keyword">int</span> <span class="hljs-title">MyDelegate</span> (<span class="hljs-params"><span class="hljs-keyword">string</span> s</span>)</span>; |
上面的委托可被用于引用任何一个带有一个单一的 string 参数的方法,并返回一个 int 类型变量。
声明委托的语法如下:
1 2 |
<span class="hljs-keyword">delegate</span> <<span class="hljs-keyword">return</span> type> <<span class="hljs-keyword">delegate</span>-name> <parameter list> |
二、实例化委托(Delegate)
一旦声明了委托类型,委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。当创建委托时,传递到 new 语句的参数就像方法调用一样书写,但是不带有参数。例如:
1 2 3 4 5 |
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">delegate</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printString</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> s</span>)</span>; ... printString ps1 = <span class="hljs-keyword">new</span> printString(WriteToScreen); printString ps2 = <span class="hljs-keyword">new</span> printString(WriteToFile); |
下面的实例演示了委托的声明、实例化和使用,该委托可用于引用带有一个整型参数的方法,并返回一个整型值。
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 32 33 34 35 36 37 38 39 |
<span class="hljs-keyword">using</span> System; <span class="hljs-function"><span class="hljs-keyword">delegate</span> <span class="hljs-keyword">int</span> <span class="hljs-title">NumberChanger</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> n</span>)</span>; <span class="hljs-keyword">namespace</span> <span class="hljs-title">DelegateAppl</span> { <span class="hljs-keyword">class</span> <span class="hljs-title">TestDelegate</span> { <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> num = <span class="hljs-number">10</span>; <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">AddNum</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> p</span>) </span>{ num += p; <span class="hljs-keyword">return</span> num; } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">MultNum</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> q</span>) </span>{ num *= q; <span class="hljs-keyword">return</span> num; } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getNum</span>() </span>{ <span class="hljs-keyword">return</span> num; } <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>) </span>{ <span class="hljs-comment">// 创建委托实例</span> NumberChanger nc1 = <span class="hljs-keyword">new</span> NumberChanger(AddNum); NumberChanger nc2 = <span class="hljs-keyword">new</span> NumberChanger(MultNum); <span class="hljs-comment">// 使用委托对象调用方法</span> nc1(<span class="hljs-number">25</span>); Console.WriteLine(<span class="hljs-string">"Value of Num: {0}"</span>, getNum()); nc2(<span class="hljs-number">5</span>); Console.WriteLine(<span class="hljs-string">"Value of Num: {0}"</span>, getNum()); Console.ReadKey(); } } } |
当上面的代码被编译和执行时,它会产生下列结果:
1 2 3 |
Value of Num: <span class="hljs-number">35</span> Value of Num: <span class="hljs-number">175</span> |
三、委托的多播(Multicasting of a Delegate)
委托对象可使用 “+” 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。”-” 运算符可用于从合并的委托中移除组件委托。
使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。下面的程序演示了委托的多播:
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 32 33 34 35 36 37 38 39 40 |
<span class="hljs-keyword">using</span> System; <span class="hljs-function"><span class="hljs-keyword">delegate</span> <span class="hljs-keyword">int</span> <span class="hljs-title">NumberChanger</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> n</span>)</span>; <span class="hljs-keyword">namespace</span> <span class="hljs-title">DelegateAppl</span> { <span class="hljs-keyword">class</span> <span class="hljs-title">TestDelegate</span> { <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> num = <span class="hljs-number">10</span>; <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">AddNum</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> p</span>) </span>{ num += p; <span class="hljs-keyword">return</span> num; } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">MultNum</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> q</span>) </span>{ num *= q; <span class="hljs-keyword">return</span> num; } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getNum</span>() </span>{ <span class="hljs-keyword">return</span> num; } <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>) </span>{ <span class="hljs-comment">// 创建委托实例</span> NumberChanger nc; NumberChanger nc1 = <span class="hljs-keyword">new</span> NumberChanger(AddNum); NumberChanger nc2 = <span class="hljs-keyword">new</span> NumberChanger(MultNum); nc = nc1; nc += nc2; <span class="hljs-comment">// 调用多播</span> nc(<span class="hljs-number">5</span>); Console.WriteLine(<span class="hljs-string">"Value of Num: {0}"</span>, getNum()); Console.ReadKey(); } } } |
当上面的代码被编译和执行时,它会产生下列结果:
1 2 |
Value of Num: <span class="hljs-number">75</span> |
四、委托(Delegate)的用途
下面的实例演示了委托的用法。委托 printString 可用于引用带有一个字符串作为输入的方法,并不返回任何东西。
我们使用这个委托来调用两个方法,第一个把字符串打印到控制台,第二个把字符串打印到文件:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<span class="hljs-keyword">using</span> System; <span class="hljs-keyword">using</span> System.IO; <span class="hljs-keyword">namespace</span> <span class="hljs-title">DelegateAppl</span> { <span class="hljs-keyword">class</span> <span class="hljs-title">PrintString</span> { <span class="hljs-keyword">static</span> FileStream fs; <span class="hljs-keyword">static</span> StreamWriter sw; <span class="hljs-comment">// 委托声明</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">delegate</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printString</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> s</span>)</span>; <span class="hljs-comment">// 该方法打印到控制台</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">WriteToScreen</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> str</span>) </span>{ Console.WriteLine(<span class="hljs-string">"The String is: {0}"</span>, str); } <span class="hljs-comment">// 该方法打印到文件</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">WriteToFile</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> s</span>) </span>{ fs = <span class="hljs-keyword">new</span> FileStream(<span class="hljs-string">"c:\\message.txt"</span>, FileMode.Append, FileAccess.Write); sw = <span class="hljs-keyword">new</span> StreamWriter(fs); sw.WriteLine(s); sw.Flush(); sw.Close(); fs.Close(); } <span class="hljs-comment">// 该方法把委托作为参数,并使用它调用方法</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendString</span>(<span class="hljs-params">printString ps</span>) </span>{ ps(<span class="hljs-string">"Hello World"</span>); } <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>) </span>{ printString ps1 = <span class="hljs-keyword">new</span> printString(WriteToScreen); printString ps2 = <span class="hljs-keyword">new</span> printString(WriteToFile); sendString(ps1); sendString(ps2); Console.ReadKey(); } } } |
当上面的代码被编译和执行时,它会产生下列结果:
1 |
The String <span class="hljs-keyword">is</span>: Hello World |