1. 程式人生 > 其它 >C#委託和事件的使用例項

C#委託和事件的使用例項

技術標籤:C#教程c#

使用委託時要先例項化,和類一樣,使用new關鍵字產生委託的新例項,然後將一個或者多個與委託簽名匹配的方法與委託例項關聯。隨後呼叫委託時,就會呼叫所有與委託例項關聯的方法。
與委託關聯可以是任何類或者結構中的方法,可以是靜態方法,只要是可以訪問的方法都可以。
參考視訊 c#教程
1.建立一個委託型別使用關鍵字delegate(委託)

public delegate void DelegateChangeStart(string str);//建立一個例項
public class Program
{
    #region 定義方法
    static void TestWriteLine1(string str)
    {
        Console.WriteLine("這裡是方法一:{0}", str);
    }
    static void TestWriteLine2(string str)
    {
        Console.WriteLine("這裡是方法二:{0}", str);
    }
    static void TestWriteLine3(string str)
    {
        Console.WriteLine("這裡是方法三:{0}", str);
    }
    #endregion
    static void Main(string[] args)
    {
        DelegateChangeStart EventChargeStartPan1, EventChargeStartPan2, EventChargeStartPan3;//定義委託變數

        //實現委託
        EventChargeStartPan1 = TestWriteLine1;
        EventChargeStartPan2 = TestWriteLine2;
        EventChargeStartPan3 = TestWriteLine3;

        //呼叫委託
        EventChargeStartPan1("1");
        EventChargeStartPan1("2");
        EventChargeStartPan1("3");

        Console.WriteLine("****************結束****************");


        Console.ReadLine();
    }
}

在這裡插入圖片描述

在這裡插入圖片描述

2.一個委託例項,可關聯多個方法:

public delegate void DelegateChangeStart(string str);//建立一個例項
public class Program
{
    #region 定義方法
    static void TestWriteLine1(string str)
    {
        Console.WriteLine("這裡是方法一:{0}", str);
    }
    static void TestWriteLine2(string str)
    {
        Console.WriteLine("這裡是方法二:{0}", str);
    }
    static void TestWriteLine3(string str)
    {
        Console.WriteLine("這裡是方法三:{0}", str);
    }
    #endregion
    static void Main(string[] args)
    {
        //DelegateChangeStart EventChargeStartPan1, EventChargeStartPan2, EventChargeStartPan3;//定義委託變數

        實現委託
        //EventChargeStartPan1 = TestWriteLine1;
        //EventChargeStartPan2 = TestWriteLine2;
        //EventChargeStartPan3 = TestWriteLine3;

        呼叫委託
        //EventChargeStartPan1("1");
        //EventChargeStartPan1("2");
        //EventChargeStartPan1("3");

        Console.WriteLine("****************結束****************");


        DelegateChangeStart EventChargeStartPan4;//定義委託變數

        EventChargeStartPan4 = TestWriteLine1;
        EventChargeStartPan4 += TestWriteLine2;
        EventChargeStartPan4 += TestWriteLine3;
        EventChargeStartPan4("四");

        Console.WriteLine("****************結束****************");

        Console.ReadLine();
    }
}

在這裡插入圖片描述
在這裡插入圖片描述

3.移除一個委託例項中的方法 使用“-”

public delegate void DelegateChangeStart(string str);//建立一個例項
public class Program
{
    #region 定義方法
    static void TestWriteLine1(string str)
    {
        Console.WriteLine("這裡是方法一:{0}", str);
    }
    static void TestWriteLine2(string str)
    {
        Console.WriteLine("這裡是方法二:{0}", str);
    }
    static void TestWriteLine3(string str)
    {
        Console.WriteLine("這裡是方法三:{0}", str);
    }
    #endregion
    static void Main(string[] args)
    {
        //DelegateChangeStart EventChargeStartPan1, EventChargeStartPan2, EventChargeStartPan3;//定義委託變數

        實現委託
        //EventChargeStartPan1 = TestWriteLine1;
        //EventChargeStartPan2 = TestWriteLine2;
        //EventChargeStartPan3 = TestWriteLine3;

        呼叫委託
        //EventChargeStartPan1("1");
        //EventChargeStartPan1("2");
        //EventChargeStartPan1("3");

        //Console.WriteLine("****************結束****************");


        DelegateChangeStart EventChargeStartPan4;//定義委託變數

        EventChargeStartPan4 = TestWriteLine1;
        EventChargeStartPan4 += TestWriteLine2;
        EventChargeStartPan4 += TestWriteLine3;
        EventChargeStartPan4("四");

        Console.WriteLine("****************結束****************");
        EventChargeStartPan4 -= TestWriteLine2;
        EventChargeStartPan4("減後的四");

        Console.ReadLine();
    }
}

在這裡插入圖片描述

在這裡插入圖片描述

其中EventChargeStartPan4 = TestWriteLine1;用“=”而不能“+=”,是因為之前EventChargeStartPan4 未例項化,可以使用下面的程式碼;
但是如果使用以下方式,會出現編譯錯誤: “DelegateChangeStart ”方法沒有采用“0”個引數的過載;
參考:http://www.tracefact.net/tech/009.html

將方法作為引數傳遞

委託可以讓方法作為引數傳遞給其它方法:

public delegate void DelegateChangeStart(string str);//建立一個例項
public class Program
{
    #region 定義方法
    static void TestWriteLine1(string str)
    {
        Console.WriteLine("這裡是方法一:{0}", str);
    }
    static void TestWriteLine2(string str)
    {
        Console.WriteLine("這裡是方法二:{0}", str);
    }
    static void TestWriteLine3(string str)
    {
        Console.WriteLine("這裡是方法三:{0}", str);
    }
    #endregion

    static void Test(DelegateChangeStart str)
    {
        if (str != null)
        {
            str("5");
        }
    }
    static void Main(string[] args)
    {
        
        DelegateChangeStart EventChargeStartPan4= TestWriteLine1;//定義委託變數

        EventChargeStartPan4 = TestWriteLine1;
        EventChargeStartPan4 += TestWriteLine2;
        EventChargeStartPan4 += TestWriteLine3;
        EventChargeStartPan4("四");

        Console.WriteLine("****************結束****************");
        DelegateChangeStart EventChargeStartPan5 = TestWriteLine1;//定義委託變數實現
        Test(EventChargeStartPan5);
        EventChargeStartPan5("五");

        Console.ReadLine();
    }
}

在這裡插入圖片描述

在這裡插入圖片描述

事件
事件自身就是委託型別,由於委託可以繫結和呼叫多個方法,所以會為事件的處理帶來方便。型別只需要對外公開事件,就可以與外部的其它地方關聯,從而實現事件訂閱要在類中宣告事件(只不過不管是不是宣告為public,它總是被宣告為private。另外,它還有兩個方法,分別是add_MakeGreet和remove_MakeGreet,這兩個方法分別用於註冊委託型別的方法和取消註冊。實際上也就是: “+= ”對應 add_MakeGreet,“-=”對應remove_MakeGreet。而這兩個方法的訪問限制取決於宣告事件時的訪問限制符。)

1.首先要定義用來作為事件封裝型別的委託,用event關鍵字來宣告事件。
2.為了允許派生類重寫引發事件的程式碼,通常會在類中宣告一個受保護的方法,習慣上命名On<事件名>

public class Program
{
    static void Main(string[] args)
    {
        
        PotInfo potinfo = new PotInfo();
        potinfo.EventChargeStartPan += Potinfo_EventChargeStartPan;//在輸入+=後面按teb鍵就會自動生成一個事件處理的方法函式
        Console.WriteLine("按下任意鍵開始執行迴圈");

        Console.ReadLine();
        potinfo.Start();//開始執行

        Console.ReadLine();
    }

    private static void Potinfo_EventChargeStartPan()
    {
        Console.WriteLine("{0}  按下空格鍵", DateTime.Now.ToString());//按下事件顯示當前時間文字輸出
    }
}


public delegate void DelegateChangeStartHelper();//定義委託
public class PotInfo
{
    //宣告事件
    public event DelegateChangeStartHelper EventChargeStartPan;
    protected virtual void OnEventChargeStartPan()
    {
        if (this.EventChargeStartPan != null)
        {
            EventChargeStartPan();
        }
    }

    public void Start()
    {
        while (true)
        {
            ConsoleKeyInfo keyinfo = Console.ReadKey();//讀取鍵值
            if (keyinfo.Key == ConsoleKey.Spacebar)//按下空格鍵觸發
            {
                OnEventChargeStartPan();
            }
            if (keyinfo.Key == ConsoleKey.Escape)//按下esc鍵退出
            {
                Console.WriteLine("{0}按下esc退出", DateTime.Now.ToString());
                break;
            }
        }
    }
}

在這裡插入圖片描述

在這裡插入圖片描述

DelegateHelper類引數
如果針對不同的事件也定義一個對應的委託,數量一旦多起來,不好管理,為了解決這個問題,.NET類庫提供了一個帶有泛型引數的事件處理委託。

public Action EventSweepCode;
public void SweepCode(string value)
{
EventSweepCode(value);
}

Action<資料型別>此委託封裝的方法的引數型別。此型別引數是逆變。即可以使用指定的型別或派生程度更低的型別。有關協變和逆變的更多資訊,請參見泛型中的協變和逆變。

public class DelegateHelper
{
public static DelegateHelper GetDelegateHelper;

    public static DelegateHelper Instance
    {
        get
        {
            if (null == GetDelegateHelper)
            {
                GetDelegateHelper = new DelegateHelper();

            }
            return GetDelegateHelper;
        }
    }


    public Action<string> EventSweepCode;
    public void SweepCode(string value)
    {
    	if(EventSweepCode!=null){
        	EventSweepCode(value);
    	}
    }
}

public class Program
{
    static void Main(string[] args)
    {

        DelegateHelper.Instance.EventSweepCode += Potinfo_EventChargeStartPan;//在輸入+=後面按teb鍵就會自動生成一個事件處理的方法函式
        Console.WriteLine("輸入任意值開始執行迴圈");
        Console.ReadLine();
        Console.WriteLine("開始執行");
        PotInfo potinfo = new PotInfo();
        potinfo.Start();//開始執行

        Console.ReadLine();
    }

    private static void Potinfo_EventChargeStartPan(string value)
    {
        Console.WriteLine("{0}  按下空格鍵", value.ToString());//按下事件顯示當前時間文字輸出
    }
}

public class PotInfo
{
    public void Start()
    {
        while (true)
        {
            ConsoleKeyInfo keyinfo = Console.ReadKey();//讀取鍵值
            if (keyinfo.Key == ConsoleKey.Spacebar)//按下空格鍵觸發
            {
                DelegateHelper.Instance.SweepCode(DateTime.Now.ToString());
            }
            if (keyinfo.Key == ConsoleKey.Escape)//按下esc鍵退出
            {
                Console.WriteLine("{0}按下esc退出", DateTime.Now.ToString());
                break;
            }
        }
    }
}

在這裡插入圖片描述

在這裡插入圖片描述