欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#中委托的基礎(chǔ)入門與實現(xiàn)方法

 更新時間:2021年08月03日 12:44:25   作者:心之凌兒  
這篇文章主要給大家介紹了關(guān)于C#中委托的基礎(chǔ)入門與實現(xiàn)方法的相關(guān)資料,究竟什么是委托,用最通俗易懂的話來講,你就可以把委托看成是用來執(zhí)行方法(函數(shù))的一個東西,需要的朋友可以參考下

前言

似乎委托對于C#而言是一種高級屬性,但是我依舊希望你就算第一次看我的文章,也能有很大的收獲。

所以本博客的語言描述盡量簡單易懂,知識點也是面向初入門對于委托不了解的學(xué)習(xí)者的。當(dāng)然如果有幸有大佬發(fā)現(xiàn)文章的錯誤點,也歡迎留言指出!

關(guān)于委托

關(guān)于委托的介紹主要來源于C#文檔:委托概述(本文章優(yōu)勢在于去掉一些不必要的細(xì)節(jié),對于初學(xué)者而言簡單高效)

委托的定義主要是下面幾個方面:

  • 委托是一種引用類型:表示對具有特定參數(shù)列表和返回類型的方法的引用
  • 在實例化委托時,你可以將其實例與任何具有兼容簽名和返回類型的方法相關(guān)聯(lián)。 你可以通過委托實例調(diào)用方法

委托本質(zhì)上來講就是將方法作為參數(shù)傳遞給其他方法的一種實現(xiàn)方式,當(dāng)然開發(fā)者也可以直接去調(diào)用方法。但是當(dāng)一個項目擴(kuò)展到足夠大時,這種直接調(diào)用的方式就會很復(fù)雜,難以維護(hù)。而委托不會,可以很方便的進(jìn)行后期的擴(kuò)展開發(fā)。只需要將自己的方法傳入已經(jīng)寫好的對應(yīng)的委托即可。而不需要再在大量的代碼中找到調(diào)用處寫入自己的方法。

關(guān)于委托的一些特點是(暫時不了解沒有關(guān)系):

  • 委托類似于 C++ 函數(shù)指針,但委托完全面向?qū)ο螅幌?C++ 指針會記住函數(shù),委托會同時封裝對象實例和方法。
  • 委托允許將方法作為參數(shù)進(jìn)行傳遞。
  • 委托可用于定義回調(diào)方法。
  • 委托可以鏈接在一起;例如,可以對一個事件調(diào)用多個方法。
  • 方法不必與委托類型完全匹配。 有關(guān)詳細(xì)信息,請參閱使用委托中的變體。
  • 使用Lambda 表達(dá)式可以更簡練地編寫內(nèi)聯(lián)代碼塊。 Lambda表達(dá)式(在某些上下文中)可編譯為委托類型。 若要詳細(xì)了解lambda 表達(dá)式,請參閱 lambda 表達(dá)式。

如果對于一個初學(xué)者,你可以簡單的理解,委托就是一個更高級的調(diào)用方法的方式,而你要學(xué)習(xí)的,就是這種方式的實現(xiàn)方法,然后后期再慢慢理解更多的細(xì)節(jié)。

委托的實現(xiàn)

一、基本實現(xiàn)方式

前面也說,委托是一個引用類型,要使用委托,肯定就需要對其進(jìn)行定義并創(chuàng)建一個委托對象,下面使用一個帶有一個參數(shù)的案例來理解委托

public class DemoDelegate
{
    	//T1:
        delegate void TestDel(string s);
        TestDel Del;
        //T4:
        static void Main(string[] args)
        {
            DemoDelegate demo = new DemoDelegate();
            demo.CreateDelObject();
            demo.Del?.Invoke("你們好");
        }
    	//T3:
        public void CreateDelObject()
        {
            Del += TestEventOne;
            Del += TestEventTwo;
        }
    	//T2:
        public void TestEventOne(string str)
        {
            Console.WriteLine(str);
        }
        public void TestEventTwo(string str)
        {
            Console.WriteLine(str);
        }    
    }

如果你是剛剛接觸委托這個概念,可能對于這些代碼的含義不是特別了解,沒關(guān)系,你可以根據(jù)注釋的順序來看代碼并理解委托的實現(xiàn)機(jī)制:

  • T1:通過delegate關(guān)鍵字定義一個委托類型TestDel,并創(chuàng)建一個實例Del
  • T2: 也很好理解,創(chuàng)建兩個測試方法,可以執(zhí)行輸出
  • T3: 是委托的關(guān)鍵,為剛剛創(chuàng)建的委托來添加事件方法
  • T4: 執(zhí)行委托實例Del,可以簡單理解為執(zhí)行該實例綁定的所有事件方法

當(dāng)然有一些語法是比較獨(dú)特的,比如說+=這樣的語法,就是一種為委托添加事件方法的方法,而對于執(zhí)行委托語句demo.Del?.Invoke("你們好");中Invoke()為執(zhí)行該委托對象內(nèi)方法的API,?則可以在Del委托對象為空時,系統(tǒng)不報錯

關(guān)于?的具體含義,可查閱:

可為空引用類型

其實委托主要是有這簡單的四步來實現(xiàn)了,通過這個案例,更加明顯的體現(xiàn)出委托將一系列方法作為參數(shù)來讓其他方法去調(diào)用的特點。

二、使用委托時的一些特殊方式

通過上面的案例,可以看出對于委托的實現(xiàn)是很簡單的,但是C#還是為我們提供了很多更加間接或者集成的用法,具體有:

1、委托實例對象的創(chuàng)建多元化:

創(chuàng)建委托類型的多種方式:

  • 直接使用New來創(chuàng)建一個對象,但是注意,在New時需要綁定直接添加一個事件方法,不然會報錯(這也是與其他引用類型不同的地方)
  • 使用直接賦值的方式創(chuàng)建
  • 定義方法名,后期添加事件方法時自動實例(上面的例子)

關(guān)于具體的實現(xiàn)代碼:

public class DemoDelegate
{
    delegate void TestDel(string str);
    //第一種:New 的同時綁定方法
    TestDel DelOne = new TestDel(TestEventOne);
    //第二種
    TestDel DelTwo = TestEventOne;
    
    static void TestEventOne(string str)
    {
        Console.WriteLine(str);
    }
}


注意,關(guān)于第三種后期綁定有一種現(xiàn)象值得留意,在使用后期綁定時,如果你是創(chuàng)建一個成員變量(全局變量)委托類型,后期綁定可以直接使用+=來增加委托綁定的方法,而你如果是創(chuàng)建一個局部變量的委托,需要先通過=來添加一個方法后,才能使用+=來增加方法,不然就會報空,如圖:

出現(xiàn)這種情況的原因在于成員變量與局部變量之間的區(qū)別,如果想要了解更多,可以執(zhí)行百度,這邊列出兩者在本案例中的區(qū)別:

成員變量:有默認(rèn)初始化值局部變量:沒有默認(rèn)初始化值,必須定義,賦值,然后才能使用。

2、事件綁定的多種方式

對于事件的綁定,可以使用的方式有很多,在不同的情況下不同的方式也有不同的優(yōu)勢與局限性,可以根據(jù)自己的需求進(jìn)行自行選擇

  • 使用方法名通過+=來添加方法,可以通過-=來刪除方法
  • 使用匿名方法
  • 使用Lambda表達(dá)式

關(guān)于第一種方法,已經(jīng)在上面表示的很清楚。

關(guān)于社會的進(jìn)步與發(fā)展,某一方面來講,是由于人類的懶來驅(qū)動的,C#開發(fā)人員可能覺得第一種方式太復(fù)雜了,于是就出現(xiàn)匿名函數(shù)的腳本,先通過代碼來看一下其實現(xiàn)方式:

public class DemoDelegate
{
    delegate void TestDel(string str);
    TestDel Del;
    static void Main(string[] args)
    {
        DemoDelegate demo = new DemoDelegate();
        //匿名方法使用方式演示
        demo.Del = delegate (string str)
        {
            Console.WriteLine("這是一個匿名方法的測試");
        };
        
    }
}

通過上面的代碼可以看出,通過匿名方式使得我們不需要重新定義方法來進(jìn)行綁定,只需要通過委托關(guān)鍵字,而省去數(shù)據(jù)類型修飾符、方法簽名等結(jié)構(gòu)

匿名方法定義(菜鳥教程):

匿名方法提供了一種傳遞代碼塊作為委托參數(shù)的技術(shù)。匿名方法是沒有名稱只有主體的方法。在匿名方法中不需要指定返回類型,它是從方法主體內(nèi)的 return 語句推斷的()

而Lambda 表達(dá)式更加極致,將能省掉的東西全部省掉,使得最終的表達(dá)式極其的簡潔:

    public class DemoDelegate
    {
        delegate void TestDel(string str);
        TestDel Del;
        static void Main(string[] args)
        {
            DemoDelegate demo = new DemoDelegate();
       		//lambda表達(dá)式,括號內(nèi)為參數(shù)變量名,如果沒有直接()
            demo.Del += (str)=>
            {
                Console.WriteLine(str);
            };
       
        }
    }

可以通過腳本看出,Lambda 表達(dá)式對于語法的節(jié)省到達(dá)了極致,去掉了所有的修飾符,包括傳入的參數(shù)的數(shù)據(jù)類型修飾符,只需要一個變量名即可,而一個委托如果沒有參數(shù),直接使用()即可,簡單到極致

注意(關(guān)于()的應(yīng)用):

如果Lambda 無參數(shù),則必須要有()
有一個參數(shù)可以去掉(),直接+= str=>{};
如果有多個參數(shù),也必須要有()

三、委托的幾種特殊實現(xiàn)方式

除了使用delegate關(guān)鍵字來實現(xiàn)委托外,C#還提供了幾種升級版的集成化的使用方式,比如Action和Func方法等等。但是注意,高的集成化往往意味著低的適配性。所以對于下面介紹幾種方式他們往往有一定的使用限制,不如delegate來的靈活,不過對于特定場景更加的簡單快捷

1,使用Action方法

在開始介紹使用方式之前,先說明一下其使用特殊

  • 對于沒有返回值的委托,簡單的理解就是不需要return(這種想法是錯誤的,但是好理解)

其實很簡單的對不對,其腳本實現(xiàn)更加簡單:

//無參數(shù)的Action委托對象的定義
Action<> actDemoOne;

//帶參數(shù)的Action委托對象的定義,參數(shù)最多十六個
Action<int> actDemoTwo;



除了定義不同外,創(chuàng)建的委托實例對于方法的綁定與執(zhí)行與標(biāo)準(zhǔn)的委托相同,其實Action本來就是通過delegate來定義的一個委托類型,但是這個定義是C#系統(tǒng)進(jìn)行定義的。

在代碼中我們很容易找到這句定義

而帶參數(shù)的類型與上面類似

這樣我們可以直接使用C#提供定義好的委托類型來創(chuàng)建我們的委托實例,這種方式的優(yōu)勢就是代碼結(jié)構(gòu)簡潔好用。不過限制就是只能綁定沒有返回值的方法

2,使用Func方法

其實Func的用法是與Action相反互補(bǔ)的,其主要的特點是有返回值,為了突出,依舊列出來

  • 主要用于沒有參數(shù)的委托類型,且必須有返回值
  • 但是同時是可以有參數(shù)的,并不是與Action完全相反

通過代碼來表述這一特點:

// int為該委托綁定方法的返回值類型,注意必須要有返回值
Func<int> funDemo;

//綁定與執(zhí)行與標(biāo)準(zhǔn)委托相同,來復(fù)習(xí)一下
public class DemoDelegate
{
        static void Main(string[] args)
        {
             DemoDelegate demo = new DemoDelegate();
            
            Func<int> funDemo;
            //為委托添加方法
            funDemo = demo.TestEventOne;
            //執(zhí)行委托
            funDemo?.Invoke();
            //依舊可以使用Lambda表達(dá)式
            funDemo += () =>
            {

                return 0;
            };
            
            /*-----------帶參數(shù)的Func用法--------*/
            Func<string,int> funDemoTwo;
            funDemoTwo = demo.TestEventTwo;            
        }
    
        public int TestEventOne()
        {
            return 0;
        }
    
    	public int TestEventTwo(string str)
        {
            Console.WriteLine(str);
            return 0;
        }       
}

上面的代碼將兩種情況放在一起解釋的,可以分開邏輯進(jìn)行理解,但是重要的是要理解帶參數(shù)的Func的用法,我們可以看到Func<string,int>有兩個數(shù)據(jù)類型的寫入,前面一個就是傳入?yún)?shù)的類型,而后面就是返回值類型,一定要區(qū)分開來

四、委托的一些特殊小知識

1、委托閉包的產(chǎn)生

在正式開始介紹閉包概念之前,先通過一個案例來發(fā)掘關(guān)于閉包產(chǎn)生的現(xiàn)象,你可以猜想一下下面的代碼的輸出結(jié)果:

    class DemoDelegate
    {
        delegate void TestDel();
        TestDel Del;
        static void Main(string[] args)
        {
            DemoDelegate demo = new DemoDelegate();     
            for (int i = 0; i < 3; i++)
            {
                demo.Del+= () =>
                {
                    Console.WriteLine(i);
                };
            }
            demo.Del?.Invoke();
    	}
    }

如果根據(jù)正常的邏輯思路去判斷,會很直接的判斷得到的輸出為:0、1、2,但是經(jīng)過執(zhí)行打印卻發(fā)現(xiàn)最終的輸出結(jié)果為:3、3、3(為啥不是2、2、2,思考一下++i與i++,或者往后看)

這樣的結(jié)果確實很奇妙,但是如果認(rèn)真思考,你可能會有一些小想法,是不是由于存儲的是數(shù)據(jù)i地址呢,而導(dǎo)致最終結(jié)果相同呢。其實可以簡單的理解成這個樣子。

如果想要更加深入的了解閉包,希望下面的一些解釋可以幫助你理解

閉包概念:

是一個函數(shù)與其他相關(guān)引用環(huán)境組合的實體,而在引用環(huán)境消失后,該函數(shù)會依舊保存從函數(shù)內(nèi)引用的變量

根據(jù)上面的例子來翻譯一下就是委托的代碼塊使用了代碼塊外的變量,而這個變量是Test()方法的局部變量,當(dāng)Test()方法執(zhí)行完畢后,這個局部變量本應(yīng)該被銷毀,但是由于閉包原因卻保存其狀態(tài)到內(nèi)存中,來保證自己后續(xù)的使用。

因此,所有的委托方法需要的變量內(nèi)存地址都指向了本應(yīng)被銷毀的局部變量i,最終的讀取就是i最后的狀態(tài),也就是全是經(jīng)過三次i++后的3

閉包需要注意的問題

如果使用必要,需要注意由于閉包而產(chǎn)生的內(nèi)存泄露的問題,由于閉包是訪問另一個函數(shù)中的變量,就會影響另一函數(shù)中的局部變量的內(nèi)存回收。而一直占用在內(nèi)存中。造成內(nèi)存泄露的后果。

但是也有另外的觀點講閉包不會造成內(nèi)存泄露。原因在于C#的垃圾回收是有相應(yīng)的處理的。由于本人對于垃圾回收機(jī)制認(rèn)識比較淺顯,目前也做不出判斷。還希望了解的人可以留言告知

2,關(guān)于事件

在C#中,也提出了事件這個概念,本質(zhì)上來講也是委托,但是是一個受限的委托

與靈活的委托不同,事件只能在定義的類內(nèi)被調(diào)用,不過可以在其他類里面進(jìn)行方法的綁定

事件的用法

在我們定義一個委托類型后,我們可以通過event創(chuàng)建一個事件實例:

通過上面的案例可以看到,使用event修飾委托實例后,只能夠在定義類中執(zhí)行委托的方法,而不能在其他類中去調(diào)用執(zhí)行

總結(jié)

關(guān)于委托的內(nèi)容還是挺多的,但是大多都是對于本質(zhì)的東西進(jìn)行的一些擴(kuò)展,在學(xué)習(xí)初期,只需要掌握關(guān)于delegate的核心的用法即可,后續(xù)再慢慢的延申擴(kuò)展

到此這篇關(guān)于C#中委托的基礎(chǔ)入門與實現(xiàn)的文章就介紹到這了,更多相關(guān)C#委托基礎(chǔ)入門內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論