理解什麼是委託、事件、Lambad表示式,從回撥說起!
接觸委託、事件等知識好長時間了,也反反覆覆看了很多資料,都是一來就給我講委託的語法、用法,卻沒有告訴我到底什麼是委託。要知道什麼是委託,先從回撥說起!
提示:該博文適合已經學習過委託、事件、Lambad表示式,但學的很模糊的朋友學習,如果你從未學習過這些東西,請看完第一節“1.什麼是回撥?”之後,通過其他更基礎的資料學習之後再繼續往下學習。在學習過程中,希望搭建一個專案跟著做一遍,這樣更好理解。如文中有錯亂之處,望指正!
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,這塊知識終於理順了,部落格也整理的幾個小時,希望對大家有用!
相關推薦
理解什麼是委託、事件、Lambad表示式,從回撥說起!
接觸委託、事件等知識好長時間了,也反反覆覆看了很多資料,都是一來就給我講委託的語法、用法,卻沒有告訴我到底什麼是委託。要知道什麼是委託,先從回撥說起! 提示:該博文適合已經學習過委託、事件、Lambad表示式,但學的很模糊的朋友學習,如果你從未學
初步理解委託、事件、匿名方法和Lambda
最經在學習LinqtoSql,然後扯到Lambda表示式,然後扯到匿名方法,然後扯到委託,最後扯到事件處理。。。後來發現對委託這個概念和事件處理這個過程理解得不是很清晰,遂得一下學習筆記。那裡說得不對,請大家多多指教! 第一部分:理解委託 委託委託,顧名思義,就是類似
【轉】【UNITY3D 遊戲開發之七】C# 中的委託、事件、匿名函式、Lambda 表示式
"委託是一個類,它定義了方法的型別,使得可以將方法當作另一個方法的引數來進行傳遞,這種將方法動態地賦給引數的做法,可以避免在程式中大量使用If-Else(Switch)語句,同時使得程式具有更好的可擴充套件性。" from: http://www.himigame.com/
.NET基礎之委託、事件、反射與特性
轉自:http://www.cnblogs.com/edisonchou/p/4827578.html 委託、事件、反射與特性 Index : (1)型別語法、記憶體管理和垃圾回收基礎 (2)面向物件的實現和異常的處理
委託、事件、單例在Unity3D中的使用
Here I demonstrate how to create delegates, events and singletons to work in conjunction. This tutorial is written for Unity3D,
.NET基礎拾遺(4)委託、事件、反射與特性
一、委託基礎 1.1 簡述委託的基本原理 委託這個概念對C++程式設計師來說並不陌生,因為它和C++中的函式指標非常類似,很多碼農也喜歡稱委託為安全的函式指標。無論這一說法是否正確,委託的的確確實現了和函式指標類似的功能,那就是提供了程式回撥指定方法的機制。 在委託內部,包含了一個指向某個方
DOM基礎知識(概念、節點樹、事件、Document)
接口 鼠標事件 所有 orm selector 設置 部分 子節點 var 1、 DOM概念 全稱為 Document Object Model,譯為文檔對象模型 D:文檔 - DOM將HTML頁面解析為一個文檔 —> document對象 O:對象 - DOM將
Vue:渲染、指令、事件、組件、Props、Slots
stop cnblogs not gui child 異步 意義 們的 最好 如果要我用一句話描述使用 Vue 的經歷,我可能會說“它如此合乎常理”或者“它提供給我需要的工具,而且沒有妨礙我的工作”。每當學習 Vue 的時
0514JS操作document對象、事件、(this)
innerhtml title AI div HA 得到 ack 多個 -a |js操作document對象|-找到對象|--document.getElementById("id名"); 通過id名找到唯一的對象 var duixiang = document.getE
監聽器、事件、事件源、事件註冊深度剖析
left local ets clas imp for 圖形 沒有 執行 AWT事件處理 事件處理機制,幾類具有典型代表意義的事件: 幾種常用事件處理機制 查看JDK Doc文檔中的 用戶圖形界面的行為 1、事件類型 (1)事件類的層次
前端(十二)—— JavaScript基礎操作:if語句、for循環、while循環、for...in、for...of、異常處理、函數、事件、JS選擇器、JS操作頁面樣式
結束 建議 prop map、set -c 表單元素 tle form collect JavaScript基礎操作 一、分支結構 1、if語句 if 基礎語法 if (條件表達式) { 代碼塊; } // 當條件表達式結果為true,會執行代碼塊;反之不執行
day031同步鎖、訊號量、事件、佇列、生成者消費者模型、Jionablequeue
multiprocessing模組主要內容: 1、守護程序 2、程序同步 1.同步鎖(*****) 2.訊號量 3.事件 3、程序通訊 1.佇列(*****) 2.生產者消費者模型,JoinableQueue, 主要在佇列的基礎上多了兩個功能:q.task_done,
Python筆記day56(jQuery)|文件處理、事件、動畫效果、each、data
1,文件處理 新增到指定元素內部的後面 $(A).append(B)// 把B追加到A $(A).appendTo(B)// 把A追加到B 新增到指定元素內部的前面 $(A).prepend(B)// 把B前置到A $(A).prependTo(
iOS原生OC向React Native傳送訊息、事件、通知
RCTEventEmitter 此篇僅獻給剛剛入門的同志們。 大家在使用React Native的時候,都會比較關心原生和React Native的互動問題。React Native給原生髮送訊息,在中文官網上講得也比較明白,按照上面的例子,相信大家都可以實現出來。但是在原生給React Native傳送
mysql小白之旅——進階篇2——儲存過程、事件、觸發器、事務、分散式事務
14.儲存過程的寫法 1)定義條件和處理 --CONDITION --HANDLER 2)游標 CURSOR --DECLARE --OPEN --FETCH --CLOSE 3)流程控制 --IF語句 --CASE語句 --LOOP語句 --LEAVE語句 相當於br
毛毛Python進階之路4——訊號量、事件、佇列、生產者消費者模型、管道、程序池及其返回值!
毛毛Python進階之路4——訊號量、事件、佇列、生產者消費者模型、管道、程序池及其返回值! 1、訊號量 上次我們講到了鎖,可以控制某段程式在同一時間內只能被一個程序鎖訪問。現在我想被兩個程序訪問,或者更多怎麼辦了?訊號量就由此而生! 這就是訊號量做的事!這段程式我可以指定
高亮:單關鍵詞、多關鍵詞、多組多關鍵詞,從簡單到複雜實現滿足多方面需求的頁面關鍵詞高亮
前言 我的前言都是良心話,還是姑且看一下吧: 別人一看這個標題,心想,“怎麼又是一個老到掉牙的需求,網上一搜一大堆解決方案啦!”。沒錯!這個需求實在老土得不能再老土了,我真不想寫這樣一種需求的文章,無奈!無奈! 現實的情況是我想這麼舊的需求網上資料一大把一大把,雖然我知道網上資料可能有坑,但是我總不信找
Java程式設計之委託代理回撥、內部類以及匿名內部類回撥(閉包回撥)
最近一直在看Java的相關東西,因為我們在iOS開發是,無論是Objective-C還是Swift中,經常會用到委託代理回撥,以及Block回撥或者說是閉包回撥。接下來我們就來看看Java語言中是如何實現委託代理回撥以及閉包回撥的。當然這兩個技術點雖然實現起來並不困難,但是,這回調在封裝一些公用元件時還是特別
Python之路(第三十八篇) 併發程式設計:程序同步鎖/互斥鎖、訊號量、事件、佇列、生產者消費者模型
一、程序鎖(同步鎖/互斥鎖) 程序之間資料不共享,但是共享同一套檔案系統,所以訪問同一個檔案,或同一個列印終端,是沒有問題的, 而共享帶來的是競爭,競爭帶來的結果就是錯亂,如何控制,就是加鎖處理。 例子 #併發執行,效率高,但競爭同一列印終端,帶來了列印錯亂 from multiproc
jQuery的屬性、css、文件處理、事件、選擇器以及jsp要點簡記
本文繼續紀錄學習jQuery,主要學習jQuery的屬性、css、文件處理、事件、選擇器,最後簡要記錄jsp知識要點。 1.JQ屬性: attr(name|pro|key,val|fn):設定或返回被