首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

委托進階:函數指標對比、接口回調限制與多路廣播實戰

     編輯:關於C#

承接上篇,針對讀者提出的關於委托與函數指標、接口回調的問題,筆者闡述觀點並進一步展示委托陣列、多路廣播及跨線程操控等進階用法。

委托與函數指標的關聯

贊同 feiyang 大神的觀點:C++ 類內部方法實質為函數指標,不佔用類記憶體。在 C# 中聲明委托實例並掛載其他類的公共方法,相當於在本類內部擁有該方法的函數指標(存儲於委托對象內)。透過委托對象調用方法時,編譯器將其視為本類聲明的方法(從安全角度論證可行)。委托並非真正的類方法,而是目標方法的代理,這正是「委托/代理」一詞的由來。

接口回調機制的侷限性

嘗試用接口回調模擬控件事件機制,代碼如下:

// 控件端
namespace InfceCalbckEvCtrl
{
    public partial class UserControl1 : UserControl
    {
        public interface ICallbackEvn { void ShowObjTxt(string Txt); }
        public ICallbackEvn ObjCallEvn;

        private void button1_Click(object sender, EventArgs e)
        {
            ObjCallEvn.ShowObjTxt("接口回調仿真事件調用成功!");
        }
    }
}

// 上層調用端
namespace InCallDemo
{
    public partial class Form1 : Form, InfceCalbckEvCtrl.UserControl1.ICallbackEvn
    {
        private void Form1_Load(object sender, EventArgs e)
        {
            userControl11.ObjCallEvn = new Form1(); // 關鍵點1:必須繼承接口
        }
        public void ShowObjTxt(string Txt) { MessageBox.Show(Txt); }
    }
}

接口回調存在兩大限制:

  1. 繼承關係限制:調用類必須同時繼承基類與控件定義的接口。
  2. 方法同名/數量限制:只能掛載與接口定義同名、同簽名的方法;若需不同功能必須重新定義接口。

相比之下,委托更靈活,使用者也更多。

6. 使用委托陣列

委托陣列展現「對象與方法兼備」特性:

delegate double CompuFun(double parama, double paramb);

class Program
{
    static void Main(string[] args)
    {
        CompuFun[] computefun = new CompuFun[2];
        computefun[0] = new CompuFun(DeleMathFuns.AddFun);
        computefun[1] = new CompuFun(DeleMathFuns.MultiplyFun);

        for (int i = 0; i < 2; i++)
        {
            Console.WriteLine("調用方法[{0}]:", i);
            Console.WriteLine("所得結果:{0}", computefun[i](5, 5));
        }
        Console.ReadLine();
    }
}

class DeleMathFuns
{
    public static double AddFun(double a, double b) { return a + b; }
    public static double MultiplyFun(double a, double b) { return a * b; }
}

可隨時調用委托對象掛載的方法,並按普通陣列管理多個委托,程序條理清晰。

7. 多路廣播委托

多個方法掛接至同一委托對象,調用時按掛接順序依次執行:

delegate void CompuFun(double parama, double paramb);

class Program
{
    static void Main(string[] args)
    {
        CompuFun computefun = null;
        computefun = new CompuFun(DeleMathFuns.AddFun);
        computefun += new CompuFun(DeleMathFuns.MultiplyFun);
        computefun(5, 5);
        Console.ReadLine();
    }
}

class DeleMathFuns
{
    public static void AddFun(double a, double b) { Console.WriteLine("AddFun方法調用結果為{0}", a + b); }
    public static void MultiplyFun(double a, double b) { Console.WriteLine("MultiplyFun方法調用結果為{0}", a * b); }
}

注意:多路廣播委托的方法返回值必須為 void,否則返回值無法分配。

8. 委托的跨線程操控

C# 不支援直接跨線程操作控件,否則拋出異常。兩種解決方案:

  1. 設置 Control.CheckForIllegalCrossThreadCalls = false(簡單但不安全,不推薦)。
  2. 使用委托配合 Control.Invoke()(安全標準做法)。

核心代碼:

private void SetText()
{
    string text = "這個控件的內容是由子線程實現的";

    if (this.textBox1.InvokeRequired)
    {
        TreadDelgate Objdelegate = new TreadDelgate(SetText);
        this.Invoke(Objdelegate, new object[] {});
    }
    else
    {
        this.textBox1.Text = text;
    }
}

深度解析:InvokeRequired 為真時,說明當前方法被視為子線程方法。透過委托在主線程再次調用同一方法,此時方法隸屬主線程,InvokeRequired 為假,直接更新 UI。這證明了「委托實例兼具對象與方法特質」是關鍵:委托作為對象在主線程建立,掛載方法後調用,使方法以主線程身份執行。

同樣邏輯適用於 [delegate].Invoke() 與 Control.Invoke():同步強制單線程執行,異步強制多線程執行,與當前環境是否多線程無關。

什麼時候使用委托?

程序效果單一,實現方式多樣。筆者提供代表性實例旨在幫助理解,每個人看待事物的方式不同,他人思想未必適合自己。願這系列文章能助你深入認識委托,總結出屬於自己的使用場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved