<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      簡單說它就是一個能把方法當參數傳遞的對象,而且還知道怎么調用這個方法,同時也是粒度更小的“接口”(約束了指向方法的簽名)。

       定義一個委托類型  Calculator:

      delegate int Calculator(int x);//定義一個委托(此委托適用于任何有著int返回類型和一個int類型參數的方法)
      class Program {
          static int Double(int x) { return x * 2; }//定義一個方法
          static void Main(string[] args) {
              //Calculator c = new Calculator(Double);//創建一個委托實例,將該此方法賦值給該委托實例
              Calculator c = Double;//簡寫
              int result = c(2);//通過委托調用方法
      
              Console.Write(result);//打印
              Console.ReadKey();
          }
      }   

      我們可以利用“委托是一個能把方法作為參數傳遞的對象”這一特點,來實現一種插件式編程。

       

      delegate int Calculator(int x);
      class Program {
          static int Double(int x) { return x * 2; }
          static void Main(string[] args) {
              int[] values = { 1,2,3,4};
              Utility.Calculate(values, Double);
      
              foreach (int i in values)
                  Console.Write(i + " "); // 2 4 6 8
              Console.ReadKey();
          }
      }
      class Utility {
          public static void Calculate(int[] values, Calculator c) {
              for (int i = 0; i < values.Length; i++)
                  values[i] = c(values[i]);
          }
      }

       

      這個例子中的Utility是固定不變的,程序實現了整數的Double功能。

      我們可以把這個Double方法看作是一個插件,如果將來還要實現諸如求平方、求立方的計算,我們只需向程序中不斷添加插件就可以了

      如果Double方法是臨時的,只調用一次,使用lambda表達式即可:

      ...Utility.Calculate(values, x => x * 2);...

      多播委托

      一個委托實例不僅可以指向一個方法,還可以指向多個方法。

      “+=” 用來添加,“-=”用來移除。

      調用時,按照方法被添加的順序依次執行。

      對于委托,+= 和 -= 對null是不會報錯的

      MyDelegate d;
      d += MyMethod1;
      // 相當于MyDelegate d = MyMethod1;

      示例:

      public delegate void ProgressReporter(int percentComplete);//定義一個委托
      public class Utility {
          //定義一個與之匹配的方法(用來執行該委托中的所有方法)
          public static void Match(ProgressReporter p) {
              if (p != null) {
                  for (int i = 0; i <= 10; i++) {
                      p(i * 10);
                      System.Threading.Thread.Sleep(100);
                  }
              }
          }
      }
      class Program {
          static void Main(string[] args) {
              ProgressReporter p = WriteProgressToConsole;
              p += WriteProgressToFile;
              Utility.Match(p);
              Console.WriteLine("Done.");
              Console.ReadKey();
          }
          //把進度打印
          static void WriteProgressToConsole(int percentComplete) {
              Console.WriteLine(percentComplete+"%");
          }
          //把進度寫到文件
          static void WriteProgressToFile(int percentComplete) {
              System.IO.File.AppendAllText("progress.txt", percentComplete + "%");
          }
      }

      靜態方法和實例方法對于委托的區別
      當一個類的實例方法被賦給一個委托對象時,在上下文中不僅要維護這個方法,還要維護這個方法所在的實例。

      但對于靜態方法,System.Delegate 類的Target屬性是Null,所以將靜態方法賦值給委托時性能更優。

      //System.Delegate 類的Target屬性指向的就是這個實例
      class Program {
          static void Main(string[] args) {
              X x = new X();
              ProgressReporter p = x.InstanceProgress;
              p(1);
              Console.WriteLine(p.Target == x); // True
              Console.WriteLine(p.Method); // Void InstanceProgress(Int32)    
        }
      } class X { public void InstanceProgress(int percentComplete) { // do something
        }
      }

      泛型委托

      含有泛型參數的委托

      public delegate T Calculator<T>(T arg);
      class Program {
          static int Double(int x) { return x * 2; }
          static void Main(string[] args) {
              int[] values = { 1, 2, 3, 4 };
              Utility.Calculate(values, Double);
      
              foreach (int i in values)
                  Console.Write(i + " "); // 2 4 6 8
              Console.ReadKey();
          }
      }
      class Utility {
          public static void Calculate<T>(T[] values, Calculator<T> c) {
              for (int i = 0; i < values.Length; i++)
                  values[i] = c(values[i]);
          }
      }

      Func 和 Action 委托

      能適用于任何返回類型和任意參數(類型和合理的個數)的通用委托(in表示參數,out表示返回結果)

      除了ref參數和out參數,基本上能適用于任何泛型委托的場景

      delegate TResult Func <out TResult> ();
      
      delegate TResult Func <in T, out TResult> (T arg);
      
      delegate TResult Func <in T1, in T2, out TResult> (T1 arg1, T2 arg2);... 一直到 T16
      
      delegate void Action ();
      
      delegate void Action <in T> (T arg);
      
      delegate void Action <in T1, in T2> (T1 arg1, T2 arg2);... 一直到 T16

      應用

      class Program {
          static int Double(int x) { return x * 2; }
          static void Main(string[] args) {
              int[] values = { 1, 2, 3, 4 };
              Utility.Calculate(values, Double);
      
              foreach (int i in values)
                  Console.Write(i + " "); // 2 4 6 8
              Console.ReadKey();
          }
      }
      class Utility {
          public static void Calculate<T>(T[] values, Func<T,T> c) 
        {    
            for (int i = 0; i < values.Length; i++)        
            values[i] = c(values[i]);
        }
      }

      委托的兼容

      類型兼容

      delegate void D1();
      delegate void D2();
      D1 d1 = Method1;
      D2 d2 = d1;
      D2 d2 = new D2(d1);

      對于具體相同的目標方法的委托是被視為相等的

      同理,對于多播委托,如果含有相同的方法和相同的順序,也被視為相等

      delegate void D();
      D d1 = Method1;
      D d2 = Method1;
      Console.WriteLine (d1 == d2); // True

      參數類型兼容

      在OOP中,任何使用父類的地方均可以用子類代替,這個OOP思想對委托的參數同樣有效

      delegate void StringAction(string s);
      class Program {
          static void Main() {
              StringAction sa = new StringAction(ActOnObject);
              sa("hello");
          }
          static void ActOnObject(object o) {
              Console.WriteLine(o); // hello
          }
      }

      返回值類型兼容

      delegate object ObjectRetriever();
      class Program {
          static void Main() {
              ObjectRetriever o = new ObjectRetriever(RetriveString);
              object result = o();
              Console.WriteLine(result); // hello    
        }
      static string RetriveString() {
          return "hello";
        } }

       

      事件

      當我們使用委托場景時,我們很希望有這樣兩個角色出現:廣播者和訂閱者。我們需要這兩個角色來實現訂閱和廣播這種很常見的場景。

      廣播者這個角色應該有這樣的功能:包括一個委托字段,通過調用委托來發出廣播。而訂閱者應該有這樣的功能:可以通過調用 += 和 -= 來決定何時開始或停止訂閱。

      事件就是描述這種場景模式的一個詞。事件是委托的一個子集,為了滿足“廣播/訂閱”模式的需求而生。

      聲明一個事件,只需在聲明一個委托對象時,加上event關鍵字;

      事件的使用和委托完全一樣,只是多了些約束;

      可以用事件的地方就一定可以用委托代替;

      事件保證了程序的安全性和健壯性。

      事件有一系列規則和約束用以保證程序的安全可控,事件只有 += 和 -= 操作,這樣訂閱者只能有訂閱或取消訂閱操作,沒有權限執行其它操作。

      如果是委托,那么訂閱者就可以使用 = 來對委托對象重新賦值(其它訂閱者全部被取消訂閱),甚至將其設置為null,甚至訂閱者還可以直接調用委托,這些都是很危險的操作,廣播者就失去了獨享控制權。

      public delegate void PriceChangedHandler(decimal oldPrice, decimal newPrice);
      public class IPhone6 {
          decimal price;
          public event PriceChangedHandler PriceChanged;
          public decimal Price {
              get { return price; }
              set {
                  if (price == value) return;
                  decimal oldPrice = price;
                  price = value;
                  // 如果調用列表不為空,則觸發。
                  if (PriceChanged != null)
                      PriceChanged(oldPrice, price);
              }
          }
      }
      class Program {
          static void Main() {
              IPhone6 iphone6 = new IPhone6() { Price = 5288 };
              // 訂閱事件
              iphone6.PriceChanged += iphone6_PriceChanged;
      
              // 調整價格(事件發生)
              iphone6.Price = 3999;
      
              Console.ReadKey();
          }
      
          static void iphone6_PriceChanged(decimal oldPrice, decimal price) {
              Console.WriteLine("年終大促銷,iPhone 6 只賣 " + price + " 元, 原價 " + oldPrice + " 元,快來搶!");
          }
      }

      事件的標準模式

      .NET 框架為事件編程定義了一個標準模式。

      設定這個標準是為了讓.NET框架和用戶代碼保持一致。

      System.EventArgs是標準模式的核心,它是一個沒有任何成員,用于傳遞事件參數的基類。

      //定義EventArgs
      public class PriceChangedEventArgs : System.EventArgs 
      {
          public readonly decimal OldPrice;
          public readonly decimal NewPrice;
          public PriceChangedEventArgs(decimal oldPrice, decimal newPrice) {
              OldPrice = oldPrice;
              NewPrice = newPrice;
          }
      }
      public class IPhone6 {
          decimal price;
          //為事件定義委托
          //必須是 void 返回類型
          //必須有兩個參數,且第一個是object類型,第二個是EventArgs類型(的子類)
          //名稱必須以EventHandler結尾
          //由于考慮到每個事件都要定義自己的委托很麻煩,.NET 框架為我們預定義好一個通用委托System.EventHandler
          //public delegate void EventHandler<TEventArgs> (object source, TEventArgs e) where TEventArgs : EventArgs;
          //如果不使用框架的EventHandler,我們需要自己定義一個
          //public delegate void PriceChangedEventHandler (object sender, PriceChangedEventArgs e);
          //如果不需要參數,可以直接使用EventHandler
          public event EventHandler<PriceChangedEventArgs> PriceChanged;
          //事件標準模式還需要寫一個受保護的虛方法來觸發事件,這個方法必須以On為前綴,加上事件名(PriceChanged),還要接受一個EventArgs參數
          protected virtual void OnPriceChanged(PriceChangedEventArgs e) {
              if (PriceChanged != null) PriceChanged(this, e);
          }
      
          public decimal Price {
              get { return price; }
              set {
                  if (price == value) return;
                  decimal oldPrice = price;
                  price = value;
                  // 如果調用列表不為空,則觸發。
                  if (PriceChanged != null)
                      OnPriceChanged(new PriceChangedEventArgs(oldPrice, price));
              }
          }
      }
      class Program {
          static void Main() {
              IPhone6 iphone6 = new IPhone6() { Price = 5288M };
              // 訂閱事件
              iphone6.PriceChanged +=iphone6_PriceChanged;
      
              // 調整價格(事件發生)
              iphone6.Price = 3999;
              Console.ReadKey();
          }
      
          static void iphone6_PriceChanged(object sender, PriceChangedEventArgs e) {
              Console.WriteLine("年終大促銷,iPhone 6 只賣 " + e.NewPrice + " 元, 原價 " + e.OldPrice + " 元,快來搶!");
          }
      }

       

      posted on 2023-02-24 11:53  費良  閱讀(37)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 国产福利微视频一区二区| 高清偷拍一区二区三区| 天天看片视频免费观看| 国产一区二区三区黄网| 衡阳县| 久久天天躁狠狠躁夜夜不卡| 免费无码一区无码东京热| 久久精品国产99国产精品澳门| 中文字幕人妻有码久视频| 亚洲熟女国产熟女二区三区| 亚洲人成网站77777在线观看| 99九九热久久只有精品| 精品人妻伦九区久久aaa片69| 亚洲第一视频区| 波多野结衣久久一区二区| 在线视频一区二区三区色| 国产aⅴ夜夜欢一区二区三区| 无码专区人妻系列日韩精品| 国产尤物精品自在拍视频首页| 久热伊人精品国产中文| 国产毛片精品av一区二区| 亚洲第一国产综合| 亚洲成aⅴ人在线电影| 欧美人妻在线一区二区| 宜川县| 亚洲男人第一无码av网站| 亚洲一区二区三区啪啪| 久久99精品九九九久久婷婷| 国内精品久久人妻无码不卡| 久久亚洲国产精品五月天| 99RE6在线观看国产精品 | 无码AV中文字幕久久专区| 亚洲国产片一区二区三区| 久久精品国产久精国产| 亚洲成av人片无码不卡播放器| 国产午夜无码视频在线观看| 国产午夜亚洲精品国产成人| 亚洲精品一二三中文字幕| 丰满少妇高潮惨叫久久久| 亚洲精品久久一区二区三区四区| 国产老女人精品免费视频|