天天看點

C# 委托與事件的差別及應用場景一、什麼是委托?二、委托使用步驟二、什麼是事件

文章目錄

  • 一、什麼是委托?
  • 二、委托使用步驟
    • 1.聲明委托
      • 1.1執行個體化委托
      • 1.2委托調用
      • 1.3委托使用場景
      • 1.4系統内置委托Action Func
      • 1.5 多點傳播委托
  • 二、什麼是事件
    • 1.聲明事件
    • 1.1事件調用
      • 1.3事件使用場景
      • 1.4 事件與設計模式

一、什麼是委托?

委托是尋址方法的.Net版本,在C++中,函數指針隻是指向記憶體位置,不是類型安全的。你無法得知這個指針實際指向什麼,參數類型、傳回類型也無從得知。而.Net委托是一個類型安全的類,它定義了傳回類型、參數類型。從IL中看它是繼承至MulticastDelegate,是以委托可以說其實就是個類。

功能上而言:當要把方法作為傳送給其他方法時,就需要使用委托

C#:

C# 委托與事件的差別及應用場景一、什麼是委托?二、委托使用步驟二、什麼是事件

IL:上圖代碼在IL編譯後的結果,可知其繼承自父類 MulticastDelegate

C# 委托與事件的差別及應用場景一、什麼是委托?二、委托使用步驟二、什麼是事件

二、委托使用步驟

1.聲明委托

定義委托就是告訴編譯器這種類型的委托表示那種類型的方法

//聲明一個委托
        public delegate void Voiddelegate( int x);// 聲明一個委托,委托所包含的方法帶有一個int參數,并且傳回Void
        public delegate void Void_delegate();//委托所包含的方法無參數,并且傳回Void
        public delegate int IntDelegate();// 委托所包含的方法無參數,并且傳回int
        public delegate int Int_Delegate(int x);// 委托所包含的方法帶有一個int參數,并且傳回Void
           

定義委托等同于定義一個新類,是以可以在任何地方定義、加上任何修飾符public、private…

1.1執行個體化委托

執行個體化時必須傳遞一個和委托的參數及傳回值相同的方法

IntDelegate intDelegate = new IntDelegate(test);
  public static int test(){
            return 1;
        }

           

1.2委托調用

intDelegate.Invoke();
            intDelegate();//兩者等價,可以省略invoke
            //參數①:AsyncCallback是異步完成的回調方法。
             //參數②是使用者自定義對象,該對象将傳遞到回調方法中
            intDelegate.BeginInvoke(null, null);//重新開一個新線程去執行方法

            intDelegate.EndInvoke(null);//檢測異步調用的結果,通常放在回掉函數中
           

1.3委托使用場景

用于解耦、減少代碼不穩定性、減少重複代碼

public class A{
        public delegate void Str_Delegate(string type);
      public void sayCat(string type){
            Console.WriteLine("cat:"+type);
      }
        public void sayDog(string type)
        {
            Console.WriteLine("Dog:" + type);
        }

        public void Say(string type,Str_Delegate str_Delegate){
              //可以在此處添加公共邏輯,避免重複代碼
            str_Delegate.Invoke(type);
        }
    }
--------------
 static void Main(string[] args)
          
        {
           
            A a = new A();
            a.Say("leslie", new A.Str_Delegate(a.sayCat));
            Console.Read();
        }
           

結果:

C# 委托與事件的差別及應用場景一、什麼是委托?二、委托使用步驟二、什麼是事件

1.4系統内置委托Action Func

Action:沒有傳回值,參數可有可無,最多支援十六個參數

Func:必須有傳回值,參數可有可無,最多支援十六個參數,最後一個參數為傳回值類型

public class A
    {
        public Action Str_Delegate;
      
        public void sayCat()
        {
            Console.WriteLine("cat:");
        }
        public void sayDog()
        {
            Console.WriteLine("Dog:");
        }

        public void Say()
        {
            Console.WriteLine("start say");
            Str_Delegate.Invoke();
        }
    }
      static void Main(string[] args)
          
        {
            A a = new A();
            a.Str_Delegate +=a.sayDog;
            a.Str_Delegate += a.sayCat;
            a.Say();
            Console.Read();
        }
           

1.5 多點傳播委托

任何一個委托都是多點傳播委托,因為繼承自父類 MulticastDelegate
           
static void Main(string[] args)
          
        {
           inInvoke(null,null);
            A a = new A();
           A.Str_Delegate str_Delegate=a.sayCat;
            str_Delegate += a.sayDog;
            str_Delegate.Invoke("leslie");
            Console.Read();
        }
           

C# 委托與事件的差別及應用場景一、什麼是委托?二、委托使用步驟二、什麼是事件

通過+=、-=進行對一個委托執行個體進行添加和移除方法。增加方法後委托就成了一個方法鍊,順序執行

str_Delegate += a.sayDog;
            //此處不能移除sayDog方法,因為屬于兩個不同的執行個體
            str_Delegate -= new A().sayDog;
           

注意:lamda表達式在多點傳播委托中也不能被移除

Func委托在形成方法鍊後隻能擷取到最後一個方法的傳回值

二、什麼是事件

事件是委托的一種應用場景,相比與委托它更安全,可以限定權限,無法在定義類的外部進行invoke調用。

1.聲明事件

public class A{
       //聲明一個事件,其實就是在委托聲明的前面加上一個Event關鍵字   
       public event Action SayHandler;
      public void sayCat(){
            Console.WriteLine("cat:");
      }
        public void sayDog()
        {
            Console.WriteLine("Dog:");
        }

        public void Say(){
            //事件調用,隻能在類内部進行
            SayHandler?.Invoke();
        }
    }
           

1.1事件調用

static void Main(string[] args)
          
        {
            A a = new A();
            a.SayHandler += a.sayCat;
            a.SayHandler += a.sayDog;
            a.SayHandler.invoke();//報錯,不能在聲明類外進行調用
            a.SayHandler = null;//報錯,不能在聲明類外設為null;
            Console.Read();
        }
           

注意:多點傳播委托和事件使用時,一次調用隻能傳給這些委托的方法相同的參數。 如果想要再調用每個方法時,參數值都不同,可以采用foreach語句,枚舉每一個調用,單獨調用相應的方法進行傳參。

1.3事件使用場景

事件通常用于winform、WPF、封裝公共邏輯(滑鼠懸停、控件變色等)

static void Main(string[] args)
          
        {
            A a = new A();
            a.SayHandler += a.sayCat;
            a.SayHandler += a.sayDog;
            a.Say();
            Console.Read();
        }
        
        public class A{
        public delegate void Str_Delegate(string type);
        public event Action SayHandler;
      public void sayCat(){
            Console.WriteLine("cat:");
      }
        public void sayDog()
        {
            Console.WriteLine("Dog:");
        }

        public void Say(){
            Console.WriteLine("start say");
            SayHandler?.Invoke();
        }
    }
           

當調用say方法時,注冊在sayhandler事件上的方法也會一并觸發

C# 委托與事件的差別及應用場景一、什麼是委托?二、委托使用步驟二、什麼是事件

1.4 事件與設計模式

1.3中的代碼其實像極了觀察者模式、釋出/訂閱
           
C# 委托與事件的差別及應用場景一、什麼是委托?二、委托使用步驟二、什麼是事件

public event Action sayHanlder就是一個channel。

a.sayHandler += a.cat就是 subscribe 對 channel的訂閱。

public void Say() 就是publisher。

将1.3的代碼換成觀察者模式:

public class A{
       public List<Action> Actions = new List<Action>();
      public void sayCat(){
            Console.WriteLine("cat:");
      }
        public void sayDog()
        {
            Console.WriteLine("Dog:");
        }

        public void Say(){
            Console.WriteLine("start say");
            Actions.ForEach(item => { item.Invoke(); });
        }
 static void Main(string[] args)
          
        {
            A a = new A();
            a.Actions.Add(a.sayCat);
            a.Actions.Add(a.sayDog);
            a.Say();
            Console.Read();
        }
           

是以兩者其實沒什麼不同,隻是在C#中的一種應用而已。

C# 委托與事件的差別及應用場景一、什麼是委托?二、委托使用步驟二、什麼是事件
c#