將方法作為方法的參數
我們先不管這個標題如何的繞口
public void GreetPeople(string name) {
// 做某些額外的事情
EnglishGreeting(name);
}
public void EnglishGreeting(string name) {
Console
}
暫且不管這兩個方法有沒有什麼實際意義
現在假設這個程序需要進行全球化
public void ChineseGreeting(string name){
Console
}
這時候
public enum Language{
English
}
public void GreetPeople(string name
//做某些額外的事情
swith(lang){
case Language
EnglishGreeting(name);
break;
case Language
ChineseGreeting(name);
break;
}
}
OK
在考慮新的解決方案之前
public void GreetPeople(string name
我們僅看 string name
如果你再仔細想想
MakeGreeting(name);
好了
public void GreetPeople(string name
MakeGreeting(name);
}
注意到 ***
NOTE
聰明的你應該已經想到了
public void EnglishGreeting(string name)
public void ChineseGreeting(string name)
如同name可以接受String類型的
於是
NOTE
本例中委托的定義
public delegate void GreetingDelegate(string name);
可以與上面EnglishGreeting()方法的簽名對比一下
現在
public void GreetPeople(string name
MakeGreeting(name);
}
如你所見
using System;
using System
using System
namespace Delegate {
//定義委托
public delegate void GreetingDelegate(string name);
class Program {
private static void EnglishGreeting(string name) {
Console
}
private static void ChineseGreeting(string name) {
Console
}
//注意此方法
private static void GreetPeople(string name
MakeGreeting(name);
}
static void Main(string[] args) {
GreetPeople(
GreetPeople(
Console
}
}
}
輸出如下
Morning
早上好
我們現在對委托做一個總結
委托是一個類
將方法綁定到委托
看到這裡
static void Main(string[] args) {
string name
name
name
GreetPeople(name
GreetPeople(name
Console
}
而既然委托GreetingDelegate 和 類型 string 的地位一樣
static void Main(string[] args) {
GreetingDelegate delegate
delegate
delegate
GreetPeople(
GreetPeople(
Console
}
如你所料
static void Main(string[] args) {
GreetingDelegate delegate
delegate
delegate
// 將先後調用 EnglishGreeting 與 ChineseGreeting 方法
GreetPeople(
Console
}
輸出為
Morning
早上好
實際上
static void Main(string[] args) {
GreetingDelegate delegate
delegate
delegate
// 將先後調用 EnglishGreeting 與 ChineseGreeting 方法
delegate
Console
}
NOTE
注意這裡
我們也可以使用下面的代碼來這樣簡化這一過程
GreetingDelegate delegate
delegate
看到這裡
GreetingDelegate delegate
delegate
delegate
但實際上
既然給委托可以綁定一個方法
static void Main(string[] args) {
GreetingDelegate delegate
delegate
// 將先後調用 EnglishGreeting 與 ChineseGreeting 方法
GreetPeople(
Console
delegate
// 將僅調用 ChineseGreeting
GreetPeople(
Console
}
輸出為
Morning
早上好
早上好
讓我們再次對委托作個總結
使用委托可以將多個方法綁定到同一個委托變量
事件的由來
我們繼續思考上面的程序
namespace Delegate {
//定義委托
public delegate void GreetingDelegate(string name);
//新建的GreetingManager類
public class GreetingManager{
public void GreetPeople(string name
MakeGreeting(name);
}
}
class Program {
private static void EnglishGreeting(string name) {
Console
}
private static void ChineseGreeting(string name) {
Console
}
static void Main(string[] args) {
//
}
}
}
這個時候
static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm
gm
}
我們運行這段代碼
Morning
早上好
現在
static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
GreetingDelegate delegate
delegate
delegate
gm
}
輸出
Morning
早上好
到了這裡
public class GreetingManager{
//在GreetingManager類的內部聲明delegate
public GreetingDelegate delegate
public void GreetPeople(string name
MakeGreeting(name);
}
}
現在
static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm
gm
gm
}
輸出為
Morning
早上好
盡管這樣做沒有任何問題
gm
既然如此
public class GreetingManager{
//在GreetingManager類的內部聲明delegate
public GreetingDelegate delegate
public void GreetPeople(string name) {
if(delegate
delegate
}
}
}
在客戶端
static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm
gm
gm
}
輸出為
Morning
早上好
盡管這樣達到了我們要的效果
在這裡
我們先看看如果把 delegate
再看看把delegate
最後
現在我們想想
於是
我們改寫GreetingManager類
public class GreetingManager{
//這一次我們在這裡聲明一個事件
public event GreetingDelegate MakeGreet;
public void GreetPeople(string name) {
MakeGreet(name);
}
}
很容易注意到
為了證明上面的推論
static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm
gm
gm
}
會得到編譯錯誤
事件和委托的編譯代碼
這時候
public event GreetingDelegate MakeGreet;
可以看到
我們再進一步看下MakeGreet所產生的代碼
private GreetingDelegate MakeGreet; //對事件的聲明 實際是 聲明一個私有的委托變量
[MethodImpl(MethodImplOptions
public void add_MakeGreet(GreetingDelegate value){
this
}
[MethodImpl(MethodImplOptions
public void remove_MakeGreet(GreetingDelegate value){
this
}
現在已經很明確了
在add_MakeGreet()方法內部
public delegate void GreetingDelegate(string name);
當編譯器遇到這段代碼的時候
public sealed class GreetingDelegate:System
public GreetingDelegate(object @object
public virtual IAsyncResult BeginInvoke(string name
public virtual void EndInvoke(IAsyncResult result);
public virtual void Invoke(string name);
}
關於這個類的更深入內容
委托
范例說明
上面的例子已不足以再進行下面的講解了
假設我們有個高檔的熱水器
現在我們需要寫個程序來模擬這個燒水的過程
namespace Delegate {
class Heater {
private int temperature; // 水溫
// 燒水
public void BoilWater() {
for (int i =
temperature = i;
if (temperature >
MakeAlert(temperature);
ShowMsg(temperature);
}
}
}
// 發出語音警報
private void MakeAlert(int param) {
Console
}
// 顯示水溫
private void ShowMsg(int param) {
Console
}
}
class Program {
static void Main() {
Heater ht = new Heater();
ht
}
}
}
Observer設計模式簡介
上面的例子顯然能完成我們之前描述的工作
這時候
// 熱水器
public class Heater {
private int temperature;
// 燒水
private void BoilWater() {
for (int i =
temperature = i;
}
}
}
// 警報器
public class Alarm{
private void MakeAlert(int param) {
Console
}
}
// 顯示器
public class Display{
private void ShowMsg(int param) {
Console
}
}
這裡就出現了一個問題
Subject
Observer
在本例中
警報器和顯示器告訴熱水器
熱水器進行燒水這一動作
熱水器知道後保留對警報器和顯示器的引用
類似這樣的例子是很多的
實現范例的Observer設計模式
我們之前已經對委托和事件介紹很多了
using System;
using System
using System
namespace Delegate {
// 熱水器
public class Heater {
private int temperature;
public delegate void BoilHandler(int param); //聲明委托
public event BoilHandler BoilEvent; //聲明事件
// 燒水
public void BoilWater() {
for (int i =
temperature = i;
if (temperature >
if (BoilEvent != null) { //如果有對象注冊
BoilEvent(temperature); //調用所有注冊對象的方法
}
}
}
}
}
// 警報器
public class Alarm {
public void MakeAlert(int param) {
Console
}
}
// 顯示器
public class Display {
public static void ShowMsg(int param) { //靜態方法
Console
}
}
class Program {
static void Main() {
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater
heater
heater
heater
}
}
}
輸出為
Alarm
Alarm
Display
// 省略
盡管上面的范例很好地完成了我們想要完成的工作
在回答上面的問題之前
委托類型的名稱都應該以EventHandler結束
委托的原型定義
事件的命名為 委托去掉 EventHandler之後剩余的部分
繼承自EventArgs的類型應該以EventArgs結尾
再做一下說明
委托聲明原型中的Object類型的參數代表了Subject
EventArgs 對象包含了Observer所感興趣的數據
上面這些其實不僅僅是為了編碼規范而已
現在我們改寫之前的范例
using System;
using System
using System
namespace Delegate {
// 熱水器
public class Heater {
private int temperature;
public string type =
public string area =
//聲明委托
public delegate void BoiledEventHandler(Object sender
public event BoiledEventHandler Boiled; //聲明事件
// 定義BoiledEventArgs類
public class BoiledEventArgs : EventArgs {
public readonly int temperature;
public BoiledEventArgs(int temperature) {
this
}
}
// 可以供繼承自 Heater 的類重寫
protected virtual void OnBoiled(BoiledEventArgs e) {
if (Boiled != null) { // 如果有對象注冊
Boiled(this
}
}
// 燒水
public void BoilWater() {
for (int i =
temperature = i;
if (temperature >
//建立BoiledEventArgs 對象
BoiledEventArgs e = new BoiledEventArgs(temperature);
OnBoiled(e); // 調用 OnBolied方法
}
}
}
}
// 警報器
public class Alarm {
public void MakeAlert(Object sender
Heater heater = (Heater)sender; //這裡是不是很熟悉呢?
//訪問 sender 中的公共字段
Console
Console
Console
}
}
// 顯示器
public class Display {
public static void ShowMsg(Object sender
Heater heater = (Heater)sender;
Console
Console
Console
}
}
class Program {
static void Main() {
Heater heater = new Heater();
Alarm alarm = new Alarm();
heater
heater
heater
heater
heater
}
}
}
輸出為
Alarm
Alarm: 嘀嘀嘀
Alarm
Alarm: 嘀嘀嘀
Alarm
Alarm: 嘀嘀嘀
Display
Display
//
From:http://tw.wingwit.com/Article/program/net/201311/12190.html