C#學習之步步高(二)認識到熟悉委託

來源:互聯網
上載者:User

標籤:c#   .net   學習   委託   delegate   

大家好,這是本系列的第二篇文章,今天我給大家帶來的是C#當中委託部分。

那麼先講講委託吧,委託是一種定義方法簽名的類型,當執行個體化委託時,您可以將其執行個體與任何具有相容簽名的方法相關聯。 您可以通過委託執行個體調用方法。

使用委託的一個好處就是像操作變數一樣操作一個方法。

下面是委託的一些特點:

  • 委託類似於 C++ 函數指標,但它們是型別安全的。
  • 委託允許將方法作為參數進行傳遞。
  • 委託可用於定義回調方法。
  • 委託可以連結在一起;例如,可以對一個事件調用多個方法。
  • 方法不必與委託簽名完全符合。

    下面 是定義個名為MyDelegate的委託,其參數類型為object,返回值為void

        public delegate void MyDelegate(object obj);

這行代碼就是用來聲明一個委託類型。再看如下代碼:

    class Program    {        public delegate void MyDelegate(object obj);        static void Main(string[] args)        {            // 在這兒,把MyDelegate看做一個類(其實它就是一個類class)            // 下面這行代碼和聲明一個對象一模一樣,因為mydelegate它就是一個對象            // 注意Method1的原型和MyDelegte一致才行(逆變和協變的內容在後面)            // 其實下面這行代碼可以簡寫為:MyDelegate mydelegate = Method1;            MyDelegate mydelegate = new MyDelegate(Method1);            // 下面這行代碼和mydelegate.Invoke(new object());沒有任何區別!            // 這行代碼的目的就是執行Method1方法            mydelegate(new object());        }        // 方法 i         public static void Method1(object o)        {            Console.WriteLine("Method1 Calling");        }    }


運行輸入結果:Method1 Calling.

那麼委託時如何像一個參數一樣傳給別的方法呢?下面這段代碼用委託回調的方式開求1~100的和:

    class Program    {        public delegate void CallBack(int number);        static void Main(string[] args)        {            // 這個函數調用後,將輸出1~100的和            Execute(100, Sum);        }        private static void Execute(int param, CallBack callBack)        {            if (callBack != null)            {                // 在這個地方調用callBack委託                callBack(param);            }        }        private static void Sum(int number)        {            int sum = 0;            for (int i = 0; i <= number; i++)            {                sum += i;            }            // 為了做示範,就暫且用這種最複雜的方法求和吧            Console.WriteLine("1~" + number + "的和為" + sum);        }    }

程式運行結果:1~100的和為5050。

那麼就有人要說了,我像調用一次Execute方法,求出1~100的和之外還求出他們的所有質數之和怎麼做呢,那麼就可以使用委託將多個方法連結到一起了:

    class Program    {        public delegate void CallBack(int number);        static void Main(string[] args)        {            // 這個函數調用後,將輸出1~100的和還有1~100之間質數的和            CallBack linkDelegate = Sum;            // 使用+=運算子,將2個方法連結一起            linkDelegate += SumOfPrimeNumber;            Execute(100, linkDelegate);        }        private static void Execute(int param, CallBack callBack)        {            if (callBack != null)            {                // 在這個地方調用callBack委託                callBack(param);            }        }        private static void Sum(int number)        {            int sum = 0;            for (int i = 0; i <= number; i++)            {                sum += i;            }            // 為了做示範,就暫且用這種最複雜的方法求和吧            Console.WriteLine("1~" + number + "的和為" + sum);        }        private static void SumOfPrimeNumber(int number)        {            int sum = 0;            for (int i = 0; i <= number; i++)            {                if (IsPrime(i))                {                    sum += i;                }            }            Console.WriteLine("1~" + number + "之間的所有質數的和為" + sum);        }        // 判斷一個數字是否為質數        private static bool IsPrime(int n)        {            for (int i = 2; i * i <= n; i++)            {                if (n % i == 0)                {                    return false;                }            }            return true;        }    }

這段代碼輸出的結果為:1~100的和為5050。1~100之間的所有質數的和為1061。


下面就來講講委託的2個重點:逆變和協變。
  • 逆變:在使用委託中,可以將方法參數從他基類修改為他的衍生類別。
  • 協變:在使用委託中,可以將方法返回值從他衍生類別修改為他的基類。
下面是一個逆變的例子:
    class Program    {        public delegate void Contravariance(string str);        static void Main(string[] args)        {            Contravariance md = Method1;            md("Contravariance");        }        static void Method1(object obj)        {            Console.WriteLine(obj + " Method1 Calling");        }    }

儘管Method1的原型和Contravariance委託定義的不一致,但是對於參數而言,Method1中的object是Contravariance中的string的基類,所以上述代碼還是能正常運行,這個就是逆變。
不過得注意下面這個例子:
    class Program    {        public delegate void Contravariance(int str);        static void Main(string[] args)        {            // 注意下面這行代碼,雖然int是object的衍生類別型,但是下面這行代碼還是會導致編譯不過,因為逆變和協變對實值型別不起作用(int為實值型別)            Contravariance md = Method1;            md(4);        }        static void Method1(object obj)        {            Console.WriteLine(obj + " Method1 Calling");        }    }
上述代碼是無法通過編譯的,在使用逆變和協變中是都不支援值類型的。

同理,下面這個是逆變的例子:

    class Program    {        public delegate object Convariance();        static void Main(string[] args)        {            // 雖然Convariance委託定義的類型傳回值和Method1不一致,但是這段代碼是可以正常啟動並執行            Convariance md = Method1;            md();        }        static string Method1()        {            return "Method1";        }    }

我們看一看如下代碼:

    public delegate void TryCode(object userData);    public delegate void WaitCallback(object state);    public delegate void TimerCallback(object state);    public delegate void ParameterizedThreadStart(object obj);
發現這些委託定義的共同點了嗎?是不是都一模一樣?事實上在.NET Framework上可以使用委託泛型,上面所有的泛型其實都可以僅使用:

    public delegate void Action<in T>(T obj);
這一個委託定義來實現就可以了。在System命名空間下有這種多達17個Action委託(這兒使用in關鍵字表示委託類型支援逆變):

    public delegate void Action();    public delegate void Action<in T1>(T1 arg1);    public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);    ...

如果是需要有參數的委託的話,可以使用如下委託:

    public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
同樣的System命名空間下也有17個Func的委託(使用out關鍵字表示委託泛型支援協變):

    public delegate TResult Func<out TResult>();    public delegate TResult Func<in T1, out TResult>(T1 arg1);    public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);    ...


最後是文本的關鍵點,為大家揭秘委託。

我們再看如下一行代碼:

    internal delegate void Feedback(int value);
其實它被編譯後,看起來像如下一個完整的類:

    internal class Feedback : System.MulticastDelegate    {        // 構造方法        public Feedback(object obj, IntPtr method);        // 這個方法的原型和委託定義的一模一樣        public virtual void Invoke(int value);        // 一下方法實現了對回調方法的非同步呼叫        public virtual IAsyncResult BeginInvoke(int value, AsyncCallback callback, Object obj);        public virtual void EndInvoke(IAsyncResult result);    }

也就是說其實委託它本身也是一個類,其繼承關係為:自訂委託->MulticastDelegate->Delegate->Object。


本文內容就講到這裡了,謝謝各位。

C#學習之步步高(二)認識到熟悉委託

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.