詳解C#中委托的概念與使用
委托的概念
委托這個名字取的神乎其神的,但實質(zhì)是函數(shù)式編程,把函數(shù)作為參數(shù)傳遞給另一個參數(shù)。對于C語言程序員來說,就是把函數(shù)指針當(dāng)作參數(shù)傳遞給另一個函數(shù)。
唯一需要注意的是,C#畢竟是強(qiáng)類型語言,用于委托的函數(shù),也相當(dāng)于變成了一種可以被傳遞的變量,所以在創(chuàng)建以及調(diào)用之前,需要聲明其數(shù)據(jù)類型
delegate int Op(int a, int b);
這個委托是一種需要傳入兩個整型參數(shù)的函數(shù),返回值也是整數(shù)。接下來對這個委托進(jìn)行實例化,最終代碼如下
int add(int a, int b) { return a + b; } var addTest = new Op(add); void calc(Op func, int a, int b) { Console.WriteLine($"func({a},)={func(a,b)}"); } calc(addTest, 2, 3); delegate int Op(int a, int b);
事先說明一下,本文所有代碼均在.Net6的頂級語句中實現(xiàn),頂級語句需要把delegate聲明放在最下面。
其中,add是一個十分質(zhì)樸的函數(shù),沒什么可說的;addTest是一個內(nèi)置了add了Op對象,其功能與add是相同的。
calc是一個以O(shè)p對象為參數(shù)的函數(shù),在這個函數(shù)中,通過Op對象func,計算了另外兩個參數(shù)a和b。
最后,調(diào)用了calc函數(shù),將addTest作為參數(shù),實質(zhì)上是計算了add(2,3),并打印了這個結(jié)果。
func(2,3)=5
>“調(diào)試停止時自動關(guān)閉控制臺”。
按任意鍵關(guān)閉此窗口. . .
多播委托
所謂多播委托,就是一個委托中通過+=運算符添加多個函數(shù)。當(dāng)然也可以通過-=運算符將原本添加的函數(shù)刪除掉。
為了演示這個功能,將上述代碼稍作更改。
int add(int a, int b){ Console.WriteLine($"{a}+={a+b}"); return a + b; } int minus(int a, int b){ Console.WriteLine($"{a}-={a-b}"); return a-b; } void calc(Op func, int a, int b) { func(a,b); } Op opTest = add; opTest += minus; opTest += add; opTest += minus; calc(opTest, 3, 4); Console.WriteLine("減去一個minus"); opTest -= minus; calc(opTest, 3, 4); delegate int Op(int a, int b);
其中Op opTest=add的寫法等價于Op opTest = new OpTest(add),但若省略new,則不可寫為var opTest = add,這個時候沒法進(jìn)行類型推斷。
輸出結(jié)果為
3+4=7
3-4=-1
3+4=7
3-4=-1
減去一個minus
3+4=7
3-4=-1
3+4=7
由此可知,委托在調(diào)用的時候,會按照+=的先后順序調(diào)用函數(shù),并將最后一個調(diào)用的函數(shù)作為返回值。
而函數(shù)在委托中以棧的方式存放,-=會先減去后存入委托中的函數(shù)。
拖動按鈕
多播委托在GUI編程中最為常用,尤其是拖動控件時。拖動控件的流程包括三個步驟
- 鼠標(biāo)點擊控件
- 鼠標(biāo)拖動控件
- 鼠標(biāo)松開控件
則對于一個控件來說,其綁定的事件會隨著鼠標(biāo)的點擊情況而發(fā)生變化
0. 鼠標(biāo)未點擊時,控件需要響應(yīng)鼠標(biāo)點擊事件
- 鼠標(biāo)點擊之后,控件需要響應(yīng)鼠標(biāo)拖動、鼠標(biāo)松開的事件
- 鼠標(biāo)拖動時,控件響應(yīng)的事件并不發(fā)生變化
- 鼠標(biāo)松開后,控件需要解綁拖動以及松開事件
接下來,實操一下,簡單起見,GUI采用winForm,在新建項目之后,拖動一個按鈕到窗口上,右鍵按鈕->屬性,可以更改一下名字和內(nèi)容,然后點擊右下角屬性
欄的小閃電,然后注冊MouseDown事件,輸入btnTest_MouseDown并按下回車之后,IDE會自動來到代碼界面,并出現(xiàn)一個空的委托函數(shù)。
private void btnTest_MouseDown(object sender, MouseEventArgs e) { }
為了理解這個東西的作用,可以在解決方案資源管理器中找到Form1.Designer.cs文件,點進(jìn)去之后可以看到下面這行代碼
this.btnTest.MouseDown += new System.Windows.Forms.MouseEventHandler(this.btnTest_MouseDown);
換言之,btnTest.MouseDown就是一個多播委托,剛剛我們的行為,為其注冊了一個名為btnTest_MouseDown的實現(xiàn),盡管這個實現(xiàn)現(xiàn)在還是空的。
若想拖動一個控件,第一步就是按下鼠標(biāo),按下鼠標(biāo)之后,需要再注冊兩個委托,分別再拖動鼠標(biāo)和松開鼠標(biāo)時起作用;而松開鼠標(biāo)和按下鼠標(biāo)的作用剛好相反,要求取消注冊拖動事件,所以下面分別實現(xiàn)這三個功能。
private void btnTest_MouseDown(object sender, MouseEventArgs e) { btnTest.MouseMove += btnTest_MouseMove; btnTest.MouseLeave += btnTest_MouseLeave; } private void btnTest_MouseLeave(object sender, EventArgs e) { btnTest.MouseMove -= btnTest_MouseMove; btnTest.MouseLeave -= btnTest_MouseLeave; } private void btnTest_MouseMove(object sender, MouseEventArgs e) { int dh = btnTest.Height / 2; int dw = btnTest.Width / 2; btnTest.Top = MousePosition.Y - this.Top - dh; btnTest.Left = MousePosition.X - this.Left - dw; }
上面需要注意一點,MouseLeave和MouseMove, MoseDown是不同類型的委托,故而創(chuàng)建函數(shù)的參數(shù)類型是不同的。
btnTest.Top為按鈕頂端距離窗口頂端的距離;MousePosition.Y表示鼠標(biāo)距離屏幕頂端的距離;this.Top表示窗口頂端距離屏幕頂端的位置,最后再減去一個按鈕高度的一半,相當(dāng)于是把按鈕的中心移動到鼠標(biāo)光標(biāo)處。這種邏輯過于簡單粗暴,實際工作時不會用到,之所以這么寫是因為簡單。
效果如下
到此這篇關(guān)于詳解C#中委托的概念與使用的文章就介紹到這了,更多相關(guān)C#委托內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VS2019 找不到資產(chǎn)文件 “xxxx\obj\project.assets.json”運行NuGet包還原以生成此文
這篇文章主要介紹了VS2019 找不到資產(chǎn)文件 “xxxx\obj\project.assets.json”運行NuGet包還原以生成此文件,本文給大家分享解決方案,感興趣的朋友跟隨小編一起學(xué)習(xí)吧2020-08-08C#線性漸變畫刷LinearGradientBrush用法實例
這篇文章主要介紹了C#線性漸變畫刷LinearGradientBrush用法,實例分析了線性漸變畫刷LinearGradientBrush的相關(guān)使用技巧,需要的朋友可以參考下2015-06-06