理解什麼是委託、事件、Lambad表示式,從回撥說起!
接觸委託、事件等知識好長時間了,也反反覆覆看了很多資料,都是一來就給我講委託的語法、用法,卻沒有告訴我到底什麼是委託。要知道什麼是委託,先從回撥說起!
提示:該博文適合已經學習過委託、事件、Lambad表示式,但學的很模糊的朋友學習,如果你從未學習過這些東西,請看完第一節“1.什麼是回撥?”之後,通過其他更基礎的資料學習之後再繼續往下學習。在學習過程中,希望搭建一個專案跟著做一遍,這樣更好理解。如文中有錯亂之處,望指正!
Demo下載地址:http://download.csdn.net/detail/wb09100310/8495759
1.什麼是回撥?
所謂回撥,是指我在A類呼叫B類裡的一個方法,在B類的這個方法執行到某個時刻或條件的時候,又返回來呼叫A類的方法。這是我對回撥的理解,先來看一個列子就好理解了。
示例:
建立一個控制檯應用程式,命名為DelegateTest,然後新增一個Product類,結構如下圖:
我們先看一下Profram.cs和Product的程式碼,再來解釋。
Program.cs程式碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DelegateTest
{
class Program
{
static void Main(string[] args)
{
Product product = new Product(){Name = "iPhone6",Price = 5288};//物件初始化語法
product.GetInfo(product);
Console.ReadKey();
}
public static void Output(Product product)
{
Console.Write("產品名稱:");
Console.WriteLine(product.Name);
Console.Write("產品價格:");
Console.WriteLine(product.Price);
}
}
}
Product.cs程式碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DelegateTest
{
/// <summary>
/// 產品類
/// </summary>
public class Product
{
/// <summary>
/// 產品名字
/// </summary>
public string Name { get; set; }
/// <summary>
/// 產品價格
/// </summary>
public int Price { get; set; }
public void GetInfo(Product product)
{
if (product != null)
{
Program.Output(product);
}
}
}
}
解釋一下,是這樣的。在Program的Main方法裡,我們通過初始化語法例項化了一個Product類,然後呼叫Product類裡的GetInfo方法得到產品資訊,而GetInfo方法又反過來呼叫Program類裡的Output方法輸出產品資訊,這就是回撥。執行結果:
這裡我們沒有用委託,就用我們很普通的方法實現了回撥。然而,我們在實際開發過程中是Product類應該被放到實體層的,而GetInfo方法應該是在業務邏輯層的,也就是說,他們直接的名稱空間是不同的。為了說明,這裡我就把Product類放到Model層,我們建立一個類庫,命名為Model,然後在Model裡新增一個類Product,並把之前Product的類拷貝過來,如果你是直接從DelegateTest裡直接把Product類檔案複製過來,那請修改Product類的名稱空間為Model,結構如圖:
這時候,我們發現Program的Main方法裡找不到Product類了,新增對Model層的引用後可以了。但是GetInfo方法裡找不到Program類了,那我們能不能在Model層反過來新增對DelegateTest的對應呢?不可以的,這時候就可以用委託實現上述回撥功能。
2.委託
怎麼定義委託,怎麼使用委託就不說了,網上有的是資料。這裡是如何理解委託,直接看程式碼,然後再解釋。
Product類中新增委託:
/// <summary>
/// 定義一個委託
/// </summary>
/// <param name="product"></param>
public delegate void OutputHandler(Product product);
/// <summary>
/// 定義委託成員變數
/// </summary>
private OutputHandler outputHandler;
/// <summary>
/// 註冊委託方法
/// </summary>
/// <param name="handler"></param>
public void RegHandler(OutputHandler handler)
{
outputHandler = handler;
}
並修改GetInfo方法為:
/// <summary>
/// 得到產品資訊
/// </summary>
/// <param name="product"></param>
public void GetInfo(Product product)
{
if (product != null && outputHandler!=null)
{
outputHandler(product);
}
}
Program裡的Main方法修改如下:
static void Main(string[] args)
{
Product product = new Product(){Name = "iPhone6",Price = 5288};//物件初始化語法
product.RegHandler(Output);//將Output方法註冊到委託中
product.GetInfo(product);
Console.ReadKey();
}
執行結果同上,解釋一下:
Product:定義了一個委託,並定義了一個委託變數,由於我們的委託變數為私有的,所以我們還需要再定義一個註冊方法到委託變數的方法RegHandler。在GetInfo中,我們修改後為通過委託變數來回撥Program中註冊到委託變數中的Output方法,這樣就輸出了產品資訊。
Program:紅色部分,將Output方法註冊到委託變數,這樣在呼叫GetInfo方法的時候自然就能回撥到Output方法了。
到這裡應該能夠理解委託中回撥是怎麼回事了,也就基本上理解什麼委託了,那麼什麼又是事件呢?
3.事件
事件實際上就是簡化了委託的寫法,主要是簡化了註冊方法。還是一樣,先看程式碼,然後再來解釋。
Product類中委託修改為:
/// <summary>
/// 定義一個委託
/// </summary>
/// <param name="product"></param>
public delegate void OutputHandler(Product product);
/// <summary>
/// 定義事件
/// </summary>
public event OutputHandler outputHandler;
刪除了RegHandler方法
Program裡的Main方法修改如下:
static void Main(string[] args)
{
Product product = new Product() { Name = "iPhone6", Price = 5288 };//物件初始化語法
product.outputHandler += Output;//註冊事件處理程式
product.GetInfo(product);
Console.ReadKey();
}
執行結果同上,加了event關鍵字之後稱之為事件,在註冊方法的時候用“+=”符號就行,可以新增多個方法。移除方法列表上的方法用“-+”符號。接下來我們再修改一下,以便讓它看上去符合微軟推薦的事件模式。
先看一下EventArgs類
// 摘要:
//System.EventArgs 是包含事件資料的類的基類。
[Serializable]
[ComVisible(true)]
public class EventArgs
{
// 摘要:
// 表示沒有事件資料的事件。
public static readonly EventArgs Empty;
// 摘要:
// 初始化 System.EventArgs 類的新例項。
public EventArgs();
}
EventArgs表示一個不發任何自定義訊息的事件。對於簡單的事件來說,傳遞的引數是EventArgs實力,如果要自定義傳遞資料引數,需要重新定義一個類,並繼承EventArgs,我們的事件要傳遞的Product類,所以定義應該如下:
public class ProductEventArgs:EventArgs
{
public readonly Product product;
public ProductEventArgs(Product p)
{
product = p;
}
}
然後我們的委託修改一下,其他不變。
/// <summary>
/// 定義一個委託
/// </summary>
/// <param name="product"></param>
public delegate void OutputHandler(object sender,ProductEventArgs e);
是不是很像ASP.NET控制元件的事件方法,sender是觸發事件的物件,e是要傳遞的事件引數。GetInfo方法修改如下,
/// <summary>
/// 得到產品資訊
/// </summary>
/// <param name="product"></param>
public void GetInfo(Product product)
{
if (product != null && outputHandler!=null)
{
outputHandler(this,new ProductEventArgs(product));
}
}
如此,Program類的Output方法修改如下,其他不變:
class Program
{
static void Main(string[] args)
{
Product product = new Product() { Name = "iPhone6", Price = 5288 };//物件初始化語法
product.outputHandler += Output;//註冊事件處理程式
product.GetInfo(product);
Console.ReadKey();
}
public static void Output(object sender,ProductEventArgs e)
{
Console.Write("產品名稱:");
Console.WriteLine(e.product.Name);
Console.Write("產品價格:");
Console.WriteLine(e.product.Price);
}
}
上面只是依照微軟的事件模式,效果和前面是一樣的。
4.匿名方法
思考一下我們發現,Output方法很少會被委託之外的任何程式呼叫,手工定義一個由委託物件呼叫的獨立方法會顯的很繁瑣,於是C#提供了匿名方法,我們可以如下改下Program類,Output方法需要了,執行結果同上:
class Program
{
static void Main(string[] args)
{
Product product = new Product() { Name = "iPhone6", Price = 5288 };//物件初始化語法
//product.outputHandler += Output;//註冊事件處理程式
product.outputHandler += delegate(object sender, ProductEventArgs e)
{
Console.Write("產品名稱:");
Console.WriteLine(e.product.Name);
Console.Write("產品價格:");
Console.WriteLine(e.product.Price);
};
product.GetInfo(product);
Console.ReadKey();
}
}
5.Lambad表示式
Lambad表示式只是用更簡單的方法來寫匿名方法,先貼程式碼再說,為了容易理解,我們再在Product類裡新增一個委託
/// <summary>
/// 定義一個委託
/// </summary>
/// <param name="product"></param>
public delegate int CompareHandler(int p);
如果價格大於5000返回1,否則返回0,Program類修改如下:
class Program
{
static void Main(string[] args)
{
Product product = new Product() { Name = "iPhone6", Price = 5288 };//物件初始化語法
product.GetInfo(product);
Product.CompareHandler c = i => i > 5000 ? 1 : 0;
int r = c(product.Price);
Console.Write(r);
Console.ReadKey();
}
}
解釋一下:i是引數列表,和定義一個方法引數列表一樣,多個引數用“,”隔開,可以加上引數型別,=>符號後面的語句是處理引數列表的語句。那如果是輸出之前的產品資訊該怎麼寫呢?,Progarm修改如下:
class Program
{
static void Main(string[] args)
{
Product product = new Product() { Name = "iPhone6", Price = 5288 };//物件初始化語法
//product.outputHandler += Output;//註冊事件處理程式
//product.outputHandler += delegate(object sender, ProductEventArgs e)
//{
// Console.Write("產品名稱:");
// Console.WriteLine(e.product.Name);
// Console.Write("產品價格:");
// Console.WriteLine(e.product.Price);
//};
//product.GetInfo(product);
product.outputHandler += (object sender, ProductEventArgs e) =>
{
Console.Write("產品名稱:");
Console.WriteLine(e.product.Name);
Console.Write("產品價格:");
Console.WriteLine(e.product.Price);
};
product.GetInfo(product);
Console.ReadKey();
}
}
OK,這塊知識終於理順了,部落格也整理的幾個小時,希望對大家有用!
相關文章
- 委託、Lambda表示式、事件系列03,從委託到Lamda表示式事件
- 委託、Lambda表示式、事件系列01,委託是什麼,委託的基本用法,委託的Method和Target屬性事件
- 委託、Lambda表示式、事件系列02,什麼時候該用委託事件
- 從IL角度徹底理解回撥_委託_指標指標
- 詳解C#委託,事件與回撥函式C#事件函式
- 委託、Lambda表示式、事件系列07,使用EventHandler委託事件
- .NET委託,事件和Lambda表示式事件
- 委託、Lambda表示式、事件系列05,Action委託與閉包事件
- 委託、Lambda表示式、事件系列04,委託鏈是怎樣形成的, 多播委託, 呼叫委託鏈方法,委託鏈異常處理事件
- javascript什麼是事件委託簡單介紹JavaScript事件
- C# 委託,事件和Lambda表示式 (轉)C#事件
- 什麼是委託(C#)C#
- C#委託回撥的一個例子C#
- C# 委託(delegate)、泛型委託和Lambda表示式C#泛型
- C#使用委託實現函式回撥,方法呼叫攔截C#函式
- 由C#委託回撥想到的二三事C#
- 委託、Lambda表示式、事件系列06,使用Action實現觀察者模式,體驗委託和事件的區別事件模式
- 事件委託事件
- 委託、事件--委託例項篇事件
- 用 Lambda表示式傳遞委託
- C#快速入門教程(17)—— 委託、事件與Lambda表示式C#事件
- 委託與事件-委託詳解(一)事件
- 資料是什麼——從數字說起
- [譯] JavaScript:回撥是什麼鬼?JavaScript
- javascript非同步回撥是什麼JavaScript非同步
- jQuery 事件委託jQuery事件
- zt 對C#下函式,委託,事件的一點理解!C#函式事件
- .net的委託和事件的直接理解 (轉)事件
- 事件模型和事件委託事件模型
- 五分鐘重溫委託,匿名方法,Lambda,泛型委託,表示式樹泛型
- JavaScript基礎——回撥(callback)是什麼JavaScript
- C# 事件委託C#事件
- C#事件委託事件
- 重中之重:委託與事件事件
- C# 委託事件C#事件
- wpf移除事件委託事件
- Js 事件原理與事件委託JS事件
- JS事件流和事件委託JS事件