日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

【C#】详解C#委托

發布時間:2025/4/9 C# 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C#】详解C#委托 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄結構:

contents structure [+]
  • 委托語法
  • 泛型委托
  • 委托鏈
  • lambda表達式
  • 揭秘委托
  • 類庫中的委托
  • 委托和反射
  • 1.委托語法

    本文會詳細闡述委托的使用,以及實現,想必讀者已經知道了函數編程中的回調機制,C#為回調機制提供了一種簡便語法,這就是委托。
    在使用委托之前需要使用delegate關鍵字進行聲明:
    比如,

    delegate void MyDelegate();

    上面定義了一個無參數,無返回的委托。定義好后,然后就可以聲明委托對象。

    MyDelegate myDelegate=new MyDelegate(SomeStaticMethod);

    上面創建了一個委托對象,這個委托對象關聯了一個方法參數。
    C#為這種操作提供了一種糖語法,就是不需要構造委托對象,如下:

    MyDelegate myDelegate=SomeStaticMethod;


    示例:
    ?

    class Program{delegate void MyDelegate();static void Main(string[] args){MyDelegate myDelegate = Method1;//委托靜態方法Method1myDelegate += new Program().Method2;//委托實例方法Method2myDelegate.Invoke();//調用委托鏈上的所有方法 Console.ReadKey();}static void Method1() {Console.WriteLine("method1 invoked");}void Method2() {Console.WriteLine("method2 invoked");}}

    2.泛型委托

    C#允許泛型委托,目的是保證任何類型的對象都可以以類型安全的方式傳給回調方法。
    例如:

    public delegate TResult CallMe<TResult,TKey,TValue>(TKey key,TValue value);

    委托的每個泛型類型參數都可以標記為協變量和逆變量。


    在這里介紹一下泛型類型參數的三種變量:
    不變量(invariant):意味著泛型類類型參數不能更改。
    逆變量(contravariant):意味著泛型類型參數可以從一個類更改為它的某個派生類,C#中使用in關鍵字標記逆變量形式的泛型類型參數。逆變量泛型類型參數T只能出現在輸入位置,作為參數。
    協變量(convariant):意味著泛型類型參數可以從一個類更改為它的某個基類,C#中使用out關鍵字標記協變量形式的泛型類型參數。逆變量泛型類型參數只能出現在輸出位置,作為返回類型。


    例如存在以下泛型類型委托:

    public delegate TResult MyFunc<in T,out TResult>(T arg);

    如果像下面定義一個委托變量:

    MyFunc(Object,ArgumentException) fn1=null;

    然后就可以將它轉變為其他委托類型變量:

    MyFunc(String,Exception) fn2=fn1;//轉化 fn2("");//調用

    3.委托鏈

    C#中提供了一種委托鏈的操作,通過委托鏈可以關聯多個方法。
    C#在實現委托鏈的時候使用了組合設計模式。C#中使用Delegate類的Combine類來完成委托的鏈接,例如:

    class Program{delegate Int32 Max(Int32 a, Int32 b);static void Main(string[] args){Max max1 = new Max(new Program().Method1);//定義委托max1Max max2 = new Max(new Program().Method2);//定義委托max2Delegate max = Delegate.Combine(max1, max2);//組合委托鏈Object obj= max.DynamicInvoke(12,13);//動態調用Console.WriteLine(obj);//13 Console.ReadLine();}Int32 Method1(Int32 a, Int32 b) {return a > b ? a : b;}Int32 Method2(Int32 a, Int32 b) {if (a > b) {return a;}return b;}}

    上面我們使用Delegate的Combine方法合并為委托鏈,其實Delegate類還提供了許多操作方法,例如:

    Delegate.remove(Delegate,Delegate);//從第一個委托鏈中移除第二個委托鏈中的委托 Delegate.DynamicInvoke(Object[]);//調用委托鏈中的所有方法 static Delegate CreateDelegate(Type type,MethodInfo method)//從給定的委托類型中,創建一個靜態方法委托

    在C#中還給Delegate重載了+=和-=操作符,可以更方便的操作委托鏈,比如:

    Max max1 = new Max(new Program().Method1);//定義委托max1Max max2 = new Max(new Program().Method2);//定義委托max2max1 += max2;

    4.lambda表達式

    Lambda表達式是C#3.0才添加的功能,是為委托添加的糖語法,lambda表達式允許以內聯的方式寫回調方法的代碼,而不需要單獨寫到方法中,例如:

    delegate Int32 Max(Int32 a, Int32 b);static void Main(string[] args){Max m = null;m += (a, b) => {return a > b ? a : b;};//lambda表達式Int32 res= m(10,11);//調用方法 Console.WriteLine(res);Console.ReadLine();}

    lambda表達式的大致格式為:(參數...)=>{方法主體}
    通常我們在寫線程的時候,我們都會定義一個WaitCallback委托,然后再關聯方法,現在我們可以像如下這樣:

    ThreadPool.QueueUserWorkItem((obj) => {Console.WriteLine("Thread:" + Thread.CurrentThread.ManagedThreadId);});Console.ReadLine();

    關于使用委托,這里有一個不成文規定,通常若是需要在回調方法寫3行以上的代碼就不用lambda表達式,而是重新定義一個方法,并為其分配名稱。若小于等于3行代碼,就可以使用lambda表達式。

    例如:

    //創建并初始化一個String數組String[] names = { "Jeff","Kristin","Aidan","Grant"};//獲取只含有小寫字母a的名稱Char charTOFind='a';names = Array.FindAll(names, (name) => { return name.IndexOf(charTOFind) >= 0; });//將每個字符串的名稱轉化為大寫names= Array.ConvertAll(names, (name) => { return name.ToUpper(); });//打印Array.ForEach(names,System.Console.WriteLine);

    5.揭秘委托

    到現在我們已經知道了如何定義委托,以及C#為委托提供的糖語法,接下來我們開始探討一下委托究竟是什么,將如下的代碼編譯為二進制文件,

    class Program{delegate Int32 MathAdd(Int32 a, Int32 b);static void Main(string[] args){MathAdd mathAdd = new MathAdd((Int32 a, Int32 b) => { return a + b; });Int32 result= mathAdd(3,2);Console.WriteLine(result);//5 Console.ReadKey();}}

    然后我們使用ildasm.exe反編譯應用程序得到il文件,就可以從CLR層面觀察出C#的委托到底是怎么回事了。

    通過這張圖片我們可以清晰的觀察出,IL代碼生成了一個靜態內部類MathAdd,然后該類派生于MulticastDelegate,到現在我們清楚了C#的委托本質上就是類。除此之外,該類提供了一個構造器方法,BeginInvoke方法,EndInvoke方法,Invoke方法。

    6.類庫中的委托

    C#已經預先定義好了豐富的委托類型供開發人員使用,在MSCorLib.dll中,有將近50個委托類型,
    例如:

    public delegate void TryCode(object userData); public delegate void WaitCallback(object state); public delegate void TimerCallback(object state); public delegate void ContextCallback(object state);
    ......

    上面這些委托都有一個共同點,就是他們都是一樣的,也就是說,只需要定義一個委托就可以了。
    .NET Framework支持泛型,C#已經為我們定義好了17個Action委托,其中包含16個泛型委托:

    public delegate void Action(); public delegate void Action<T>(T arg); public delegate void Action<T1,T2>(T1 arg1,T2 arg2); public delegate void Action<T1,T2,T3>(T1 arg1,T2 arg2,T3 arg3); ...... public delegate void Action<T1,.....,T16>(T1 arg1,......,T16 arg16);

    除了Action委托,C#還為我們定義了Func委托,允許回調方法返回值:

    public delegate TResult Func<TResult>(); public delegate TResult Func<T,TResult>(T arg); public delegate TResult Func<T1,T2,TResult>(T1 arg1,T2 arg2); public delegate TResult Func<T1,T2,T3,TResult>(T1 arg1,T2 arg2,T3 arg3); ...... public delegate TResult Func<T1,.....,T16,TResult>(T1 arg1,.....,T16 arg16);

    上面列出了C#定義的Action和Func委托,如果涉及到委托最好是使用這些委托類型,而不是重新定義,這樣可以減少程序集的大小。

    但是如果涉及到ref或out參數,那么就只有自己定義了。
    比如:

    delegate void Bar(ref Int32 z);

    7.委托和反射

    通常情況下,使用委托都應該知道委托的原型,但是反射提供了另一種可能來使用委托。
    在MethodInfo中提供了一個createDelegate方法,運行在編譯器不知道委托的所有信息下提前創建委托。

    public virtual Delegate CreateDelegate(Type delegateType);public virtual Delegate CreateDelegate(Type delegateType, object target);

    在創建好Delegate對象后,就可以通過調用對象的DynamicInvoke方法來調用委托。

    public Object DynamicInvoke(params Object[] args);

    下面的展示了如何使用反射來調用委托:

    class Program{static void Main(string[] args){//定義一個Func<Int32,Int32,Int32>類型的數據Type type=typeof(Func<Int32,Int32,Int32>);//獲得Program實例的Max方法MethodInfo methodInfo = typeof(Program).GetMethod("Max", BindingFlags.Instance|BindingFlags.Public);//創建委托Delegate d = methodInfo.CreateDelegate(type, new Program());//調用Object res = d.DynamicInvoke(13, 12);Console.WriteLine(res);//13 Console.ReadKey();}public Int32 Max(Int32 a, Int32 b){return a > b ? a : b;}}

    ?

    轉載于:https://www.cnblogs.com/HDK2016/p/7771404.html

    總結

    以上是生活随笔為你收集整理的【C#】详解C#委托的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。