C#委托學習筆記


1、C#委托是什么

c#中的委托可以理解一種類,這種類實例化后可以將函數的包裝成一個變量(該變量就變成了對該函數的“引用”),它使得這個變量(函數)可以作為參數來被傳遞,這在作用上相當於c中的函數指針。c用函數指針獲取函數的入口地址,然后通過這個指針來實現對函數的操作。

委托的定義和方法的定義類似,只是在定義的前面多了一個delegate關鍵字。如下定義:

public delegate void MyDelegate(int para1, string para2);

委托能包裝的方法是有一定限制的,例如能被前面的委托類型MyDelegate包裝的方法需要滿足以下條件:

1.方法的返回類型必須為void;

2.方法必須有兩個參數,並且第一個參數應為int類型,第二個參數為string類型。

總結:可以被委托包裝的方法必須滿足以下規則:

1.方法的簽名必須與委托一致,方法簽名包括參數的個數、類型和順序;

2.方法的返回類型要和委托一致,注意,方法的返回類型不屬於方法簽名的一部分。

2、委托的使用

//委托使用的演示
class Program
{        
    public delegate void MyDelegate(int para1, int para2);  //1.使用delegate關鍵字來定義一個委托類型
    static void Main(string[] args)
    {            
        MyDelegate d;   //2.聲明委托變量d
        
        d = new MyDelegate(new Program().Add);  //3.實例化委托類型,傳遞的方法也可以為靜態方法,這里傳遞的是實例方法
        
        MyMethod(d);    //4.委托類型作為參數傳遞給另一個方法

        Console.ReadKey();
    }

    void Add(int para1, int para2)
    {
        int sum = para1 + para2;
        Console.WriteLine("兩個數的和為:" + sum);
    }

    private static void MyMethod(MyDelegate mydelegate)
    {            
        mydelegate(1, 2);   //5.在方法中調用委托
    }
}

從以上代碼可以看出,使用委托的步驟為:定義委托類型—聲明委托變量實例化委托將實例作為參數傳遞給另一個方法該方法調用委托。如下具體分析委托的使用過程。

(1)定義委托類型: public delegate void MyDelegate(int a, int b);。其定義方式類似於方法的定義,只是多了一個delegate關鍵字。

(2)聲明委托變量:MyDelegate d;既然委托是一種類型,那么可以使用委托來聲明一個委托變量,相當於int a;

(3)實例化委托: d = new MyDelegate(new Program().Add);。第二步只是聲明了委托變量,但並沒有將它實例化。類的實例化使用new關鍵字來實現,而委托也屬於一種“類”,所以委托的實例化也使用new關鍵字來進行的。這里需要注意的是,委托的實例化是用一個方法名(不能帶左右括號)作為參數,並且該方法的定義必須符合委托的定義,即該方法的返回類型、參數個數和類型必須與委托定義中的一樣。這樣,前面3步就好比構造了一個律師對象,而方法InstanceMethod好比是當事人的方法。

(4)作為參數傳遞給方法:MyMethod(d);。委托使用得在C#中,可以把一個方法作為另一個方法的參數,而委托可以看作是一個包裝方法的對象。

(5)在方法中調用委托。MyMethod(d);。委托使用得在c#中,可以把一個方法作為另一個方法的參數,而委托可以看作是一個包裝方法的對象。

總結:在使用委托時,需要注意以下幾個問題。

1.在第三步中,被傳遞的方法的定義必須與委托定義相同,即方法的返回類型和參數個數、參數類型都必須與委托相同。並且,傳遞的是方法名,方法名后不能帶有左右括號。

2.在第五步中,委托的調用與方法調用類似,傳遞的實參類型和個數必須與委托定義一致。

3.由於委托是方法的包裝類型,所以對委托的調用也就是對其所包裝的的方法的調用,上面第5步時間上是調用了Add方法來對傳入的實參進行計算。

3、委托鏈的使用

委托鏈其實就是委托類型,只是委托鏈把多個委托鏈接在一起而已,也就是說,我們把鏈接了多個方法的委托稱為委托鏈或多路廣播委托。如下:

public delegate void DelegateTest();
static void Main(string[] args)
{
    //用靜態方法來實例化委托
    DelegateTest dtstatic = new DelegateTest(Program.method1);      
    DelegateTest dtinstance = new DelegateTest(new Program().method2);
    
    DelegateTest delegatechain = null;  //定義一個委托對象,一開始初始化為null,即不代表任何方法。

    //使用 “+”符號鏈接委托,鏈接多個委托后就成為了委托鏈
    delegatechain += dtstatic;
    delegatechain += dtinstance;

    //調用委托鏈
    delegatechain();    // 輸出兩行"這是靜態方法"和"這是實例方法"
    Console.Read();
}
private static void method1()
{
    Console.WriteLine("這是靜態方法");
}

private void method2()
{
    Console.WriteLine("這是實例方法");
}

從委托鏈中移除委托

//使用 “+”符號鏈接委托,鏈接多個委托后就成為了委托鏈
delegatechain += dtstatic;
delegatechain += dtinstance;

//使用 “-”運算符 移除委托 
delegatechain -= dtstatic;

4、什么要使用委托

上一章中我們可能會很疑惑,為什么需要委托?為什么不直接在MyMethod方法里直接調用Add方法,反而要實例化一個委托對象來完成調用呢?這豈不是自找麻煩嗎?

當然,c#引入委托並不是自找麻煩。委托是c#最好的一個特性,它為后來的很多特性都打下了基礎。委托使得一個方法可以作為另一個方法的參數進行傳遞,這就是委托最大的作用。如下例子:

例如我們要實現一個打招呼的方法,而每個國家打招呼的方式都不一樣,剛開始我們可能會像下面這樣實現打招呼的方法:

public void Greeting(string name, string language)
{
    switch (language)
    {
        case "zh-cn":
            ChineseGreeting(name);
            break;
        case "en-us":
            EnglishGreeting(name);
            break;
        default:
            EnglishGreeting(name);
            break;
    }
}

public void EnglishGreeting(string name)
{
    Console.WriteLine("Hello, " + name);
}

public void ChineseGreeting(string name)
{
    Console.WriteLine("你好, " + name);
}

若后續我們需要添加德國、日本等打招呼方法,就必須修改Greeting方法內的case語句,來適應新的需求,這樣特別不方便。有了委托,我們就可以把函數作為參數,並像如下代碼實現Greeting方法:

public delegate void GreetingDelegate(string name);
static void Main(string[] args)
{
    //引入委托
    Program p = new Program();
    p.Greeting("小葉", p.ChineseGreeting);        // 將所使用的的方法ChineseGreeting作為參數傳遞
    p.Greeting("Tommy Li", p.EnglishGreeting);
    Console.Read();
}

public void Greeting(string name, GreetingDelegate callback)
{
    callback(name); // 調用ChineseGreeting方法
}
public void EnglishGreeting(string name)
{
    Console.WriteLine("Hello, " + name);
}
public void ChineseGreeting(string name)
{
    Console.WriteLine("你好, " + name);
}

文章轉載自:【c# 學習筆記】c#委托是什么

5、例子

class Program
{
    static void Main(string[] args)
    {
        Bookstore XinHua = new Bookstore(); // 實例化一個新化書店
        Reader LiNing = new Reader();       // 實例化一個讀者李寧

        // 以new關鍵字實例化一個委托綁定到onpublish事件
        // 傳遞的方法可以是“靜態方法”,也可以是“實例方法”
        XinHua.onpublish += new Bookstore.publish(LiNing.issue);
        XinHua.issue();
        Console.ReadKey();
    }
}

public class Bookstore
{
    public delegate void publish(); //聲明委托
    public event publish onpublish; //聲明委托注冊的事件

    //聲明觸發方法
    public void issue()
    {
        Console.WriteLine("書店發布了一本雜志");
        this.onpublish();
    }
}

public class Reader
{
    // 定義收到雜志的方法
    public void issue()
    {
        Console.WriteLine("我收到了一本雜志");
    }
}

運行結果:

示例2

class Program
{
    static void Main(string[] args)
    {
        Bookstore XinHua = new Bookstore();  // 實例化一個新化書店
        Reader LiNing = new Reader("李寧");  // 實例化一個讀者李寧,訂閱了電腦類雜志
        Reader LiSi = new Reader("李四");    // 實例化一個讀者李四,訂閱了英語類雜志

        // 李寧只訂閱電腦類雜志事件
        XinHua.on_publish_computer += new Bookstore.publish_computer(LiNing.received_book);

        // 李四兩種雜志都訂閱了
        XinHua.on_publish_computer += new Bookstore.publish_computer(LiSi.received_book);
        XinHua.on_publish_english += new Bookstore.publish_english(LiSi.received_book);

        XinHua.issue_computer();
        XinHua.issue_english();

        Console.ReadKey();
    }
}

public class Bookstore
{
    // 委托有些類“似於”類的靜態方法, 可以通過Bookstore.publish_computer進行訪問
    public delegate void publish_computer(string bookname); //聲明電腦的委托
    public event publish_computer on_publish_computer;      //聲明委托注冊的事件

    //發行電腦的觸發方法
    public void issue_computer()
    {
        Console.WriteLine("書店發布了一本電腦類雜志");
        this.on_publish_computer("《電腦周報》");
    }

    public delegate void publish_english(string bookname); //聲明自己的委托        
    public event publish_english on_publish_english;      //聲明委托注冊的事件

    //發行電腦的觸發方法
    public void issue_english()
    {
        Console.WriteLine("書店發布了一本英語類雜志");
        this.on_publish_english("《英語周報》");
    }
}

public class Reader
{
    public string name;
    public Reader(string n) { this.name = n; }
    // 定義收到雜志的方法
    public void received_book(string bookname)
    {
        Console.WriteLine(this.name + "收到了一本雜志" + bookname);
    }
}

運行結果:

示例3

class Program
{
    static void Main(string[] args)
    {
        Bookstore XinHua = new Bookstore("新華書店"); // 實例化一個新化書店
        Reader LiNing = new Reader("李寧");           // 實例化一個讀者李寧,訂閱了電腦類雜志
        Reader LiSi = new Reader("李四");             // 實例化一個讀者李四,訂閱了英語類雜志

        // 李寧和李四訂閱電腦類雜志事件
        XinHua.PubComputer += new Bookstore.PubComputerEventHandler(LiNing.received_book);
        XinHua.PubComputer += new Bookstore.PubComputerEventHandler(LiSi.received_book);

        // 李四訂閱了英語類雜志事件
        XinHua.PubEnglish += new Bookstore.PubEnglishEventHandler(LiSi.received_book);

        // 手動觸發執行發布雜志事件
        XinHua.issueComputer("電腦周刊", Convert.ToDateTime("2019.10.29"));
        XinHua.issueEnglish("英語周刊", Convert.ToDateTime("2018.09.29"));
        Console.ReadKey();
    }
}
    
// 發布事件類
public class PubEventArgs : EventArgs
{
    public string bookName;
    public DateTime bookTime;
    //構造函數
    public PubEventArgs(string name, DateTime time) { this.bookName = name; this.bookTime = time; }
}

public class Bookstore
{
    public string name;
    public Bookstore(string n) { this.name = n; }

    // 委托有些類似於類的靜態方法, 可以通過Bookstore.PubComputerEventHandler進行訪問
    // 委托實際上是一種類,可以使用new關鍵字實例化
    // 實例化后,就是對函數包裝(引用),使得函數可以作為參數傳遞或賦值。
    public delegate void PubComputerEventHandler(object sender, PubEventArgs e); //聲明電腦的委托
    public event PubComputerEventHandler PubComputer;                            //聲明委托注冊的事件

    //發行電腦的觸發方法
    public void issueComputer(string bookname, DateTime booktime)
    {
        Console.WriteLine("書店發布了一本電腦類雜志");
        this.PubComputer(this, new PubEventArgs(bookname, booktime));
    }

    public delegate void PubEnglishEventHandler(object sender, PubEventArgs e); //聲明自己的委托        
    public event PubEnglishEventHandler PubEnglish;                             //聲明委托注冊的事件

    //發行電腦的觸發方法
    public void issueEnglish(string bookname, DateTime booktime)
    {
        Console.WriteLine("書店發布了一本英語類雜志");
        this.PubEnglish(this, new PubEventArgs(bookname, booktime));
    }
}

public class Reader
{
    public string name;
    public Reader(string n) { this.name = n; }

    // 定義收到雜志的方法,參數不是一個簡單的變量而是PubEventArgs實例
    public void received_book(object sender, PubEventArgs e)
    {
        Bookstore bs = (Bookstore)sender;
        Console.WriteLine(string.Format("{0}收到了{1}書店發布的《{2}》 發布時間:{3}", this.name, bs.name, e.bookName, e.bookTime));
    }
}

允行結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM