【Unity|C#】基礎篇(8)——委托(Delegate)/ 事件(Event)


【學習資料】

  《C#圖解教程》(第13~14章)https://www.cnblogs.com/moonache/p/7687551.html
  電子書下載:https://pan.baidu.com/s/1mhOmBG0

  • 其他

    > 委托與事件詳解Part1:http://www.tracefact.net/tech/009.html

    > 委托與事件詳解Part2:http://www.tracefact.net/tech/029.html 

 

【內容】 

    • 委托(Delegate)
      • 定義:類似C++的函數指針
      • 委托多播
      • 委托綁定函數及執行原理
    • 事件(Event)
      • 定義:類似 字段與屬性 的關系
      • 事件訪問器(add/remove)
      • 為什么使用事件?

 


【委托Delegate】

  • 定義
    • 類似C++的函數指針,delegate相當於是 指向某對象的某個函數,引用類型變量
    • 委托和類一樣,也需要 聲明、創建、賦值
      • 聲明委托類型(像類一樣聲明一個委托類型)  public delegate [函數返回值] 委托名稱(參數1,參數2...);
      • 創建委托變量  MyDelegate opt = new MyDelegate(AddNum);  (實際綁定的是:this.AddNum)
      • 重新賦值  opt = MultNum;  (實際綁定的是:this.MultNum)
    • 執行委托:就是執行引用的 委托函數
    • 委托可以:動態修改引用的函數
    • // 聲明:一個可以指向 返回類型為int,帶2個int參數的 函數
      public delegate int MyDelegate(int a, int b);
      
      // 相加函數
      public int AddNum(int a, int b)
      {
          return (a + b);
      }
      // 相乘函數
      public int MultNum(int a, int b)
      {
          return (a * b);
      }
      
      void Start()
      {
          // 創建:指向不同函數的委托類型
          MyDelegate opt = new MyDelegate(AddNum);
          Debug.Log(opt(2, 5)); // 執行委托函數: 7 // 運行時,可以改變賦值
          opt = MultNum;
          Debug.Log(opt(2, 5)); // 執行委托函數: 10
      }

 

  • 委托多播
    • 創建的委托類型變量 opt 可以存儲 函數調用列表(綁定多個委托函數)
    • 通過 "+",或"+="添加 一個函數引用
    • 通過 "-",或"-="  :移除 某個函數的引用
    • 執行委托:會執行所有添加綁定的 委托函數
    • public delegate void MyDelegate(int a, int b);
      
      // 輸出相加結果
      public void PrintAddNum(int a, int b)
      {
          Debug.Log("PrintAddNum:" + (a + b));
      }
      // 輸出相乘結構
      public void PrintMultNum(int a, int b)
      {
          Debug.Log("PrintMultNum:" + (a * b));
      }
      
      void Start()
      {
          // 創建:指向不同函數的委托類型
          MyDelegate opt = new MyDelegate(PrintAddNum);
      
          // 通過+=添加委托函數
          // 也可以直接相加 opt = PrintAddNum + PrintMultNum;
          opt += PrintMultNum;
          // 執行委托,會按添加的順序,分別執行PrintAddNum和PrintMultNum
          opt(2, 5);
      
          // 通過-=移除對某函數的引用
          opt -= PrintAddNum;
          // 再次執行委托,只執行了PrintMultNum
          opt(2, 5);
      }
      
      // 輸出
      //  PrintAddNum: 7
      //  PrintMultNum: 10
      //  PrintMultNum: 10

 

  • 委托綁定函數及執行原理
    • 綁定委托函數
      • 可以通過:“=”、“+=”、“-=”、“+”、“-”,來重新給委托綁定函數,或添加刪除函數
      • 綁定普通函數:同時會將對象(this)引用存儲起來
      • 綁定靜態函數:無需存儲對象(this)引用
      • class Person
        {
            public delegate void MyDelegate(int a, int b);
            public MyDelegate myDelegate;
        
            // 普通函數,綁定時需要有明確對象(this)
            public void Func1(int a, int b) { ... }
            // 靜態函數,通過類名.Func2綁定
            public static void Func2(int a, int b) { ... }
        }
        
        void Start()
        {
            Person myPerson = new Person();
        
            //myPerson.myDelegate += Person.Func1;  // 報錯,Func1需要對象(this)
            myPerson.myDelegate += Person.Func2;
        
            myPerson.myDelegate += myPerson.Func1;
            //myPerson.myDelegate += myPerson.Func2; // 報錯,Func2是靜態函數
        }
    • 執行方式
      • 通過"+" 或 "+=" 的順序,依次執行綁定的委托函數
      • 普通函數:相當於 調用 綁定對象引用(this)的函數,包含了對象的this引用
      • 靜態函數:相當於 調用 綁定的委托函數;
      • // 聲明委托類型
        public delegate void MyDelegate();
        
        class Person
        {
            public string name;
            public void PrintName()
            {
                Debug.Log(name);
            }
        }
        
        void Start()
        {
            // 創建2個對象
            Person myPerson = new Person();
            Person myPerson2 = new Person();
            myPerson.name = "Alice";
            myPerson2.name = "Bob";
        
            // 創建委托變量
            MyDelegate myDelegate = new MyDelegate(myPerson.PrintName);
            // 多播:委托函數
            myDelegate += myPerson2.PrintName;
        
            // 執行委托
            myDelegate();
        }
        
        // 輸出 // Alice // Bob

         

 


【事件】 

  • 定義 
    • 事件是對委托的封裝,關系和字段與屬性(Property) 一樣
    • 事件是基於委托,所以首要聲明委托,再定義事件
    • // 聲明委托類型
      public delegate void MyDelegate(int a, int b);
      // 定義事件
      public event MyDelegate myEvent;
    • 注:事件的聲明只能在類內部,不能在函數內
    • 原理
      • 實際上與屬性一樣,定義一個事件,會自動創建一個隱藏(private)的委托類型變量
      • 並包含了add_xxx("+=")和remove_xxx("-="),用來添加/刪除 委托函數
    • 事件的執行:只能在定義事件的類內部執行
    • // 聲明委托類型
      public delegate void MyDelegate(int a, int b);
      
      class Person
      {
          // 定義事件
          public event MyDelegate myEvent;
      
          public void FireEvent(int a, int b)
          {
              if (myEvent != null)
                  myEvent(a, b); // 必須在定義事件的類內部執行
          }
      }
      
      public void PrintAddNum(int a, int b)
      {
          Debug.Log("PrintAddNum:" + (a + b));
      }
      public void PrintMultNum(int a, int b)
      {
          Debug.Log("PrintMultNum:" + (a * b));
      }
      
      void Start()
      {
          Person person = new Person();
          person.myEvent += PrintAddNum;
          person.myEvent += PrintMultNum;
      
          //person.myEvent(2, 5); // 報錯,無法在定義事件的類外部執行
          person.FireEvent(2, 5); // 正確
      }
    • 注:事件不能在類的外部使用賦值“=”,但是在類內部可以重新賦值“=”
    • 事件與委托一樣,也支持多播:可以通過“+=”、“-=” 來添加事件、刪除事件

 

  •  事件訪問器(add / remove)
    • 事件與委托的關系,與 字段與屬性的關系是一樣的,所以也有訪問器
    • 關鍵字: add  remove 
    • public event MyDelegate myEvent
      {
          add
          {
              ...    //執行 += 運算符的代碼
          }
          remove
          {
              ...    //執行 -= 運算符的代碼
          }
      }

 

  • 為什么使用事件?
    • 對委托的封裝
      • 對外只能通過事件來 添加/刪除 綁定的委托函數
      • 事件只能在定義事件的 類內部執行
    • 滿足觀察者模式(發布者-訂閱者)
    • 當然不使用事件,也可以實現對委托的封裝
      • 將委托定義為private,然后對外提供添加/刪除委托函數的方法(相當於手動實現事件中的add_xxx和remove_xxx)
      • // 聲明委托類型
        public delegate void MyDelegate(int a, int b);
        
        class Person
        {
            // 定義一個私有委托變量
            public MyDelegate myDelegate;
            // 添加
            public void AddEvent(MyDelegate d)
            {
                myDelegate += d;
            }
            // 刪除
            public void RemoveEvent(MyDelegate d)
            {
                myDelegate -= d;
            }
            // 執行
            public void FireEvent(int a, int b)
            {
                if (myDelegate != null)
                    myDelegate(a, b); // 必須在定義事件的類內部執行
            }
        }
        
        public void PrintAddNum(int a, int b)
        {
            Debug.Log("PrintAddNum:" + (a + b));
        }
        public void PrintMultNum(int a, int b)
        {
            Debug.Log("PrintMultNum:" + (a * b));
        }
        
        void Start()
        {
            Person person = new Person();
        
            person.AddEvent(PrintAddNum);       // this.PrintAddNum
            person.RemoveEvent(PrintMultNum);   // this.PrintMultNum
        
            person.FireEvent(2, 5);
        }

         

 


免責聲明!

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



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